<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>Discovery</title>
        <meta name="robots" content="noindex" />


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="Discover the world of microcontrollers through Rust">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="favicon.svg">
        <link rel="shortcut icon" href="favicon.png">
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        <link rel="stylesheet" href="custom.css">

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="index.html">Introduction</a></li><li class="chapter-item expanded "><a href="01-background/index.html"><strong aria-hidden="true">1.</strong> Background</a></li><li class="chapter-item expanded "><a href="02-requirements/index.html"><strong aria-hidden="true">2.</strong> Hardware/knowledge requirements</a></li><li class="chapter-item expanded "><a href="03-setup/index.html"><strong aria-hidden="true">3.</strong> Setting up a development environment</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="03-setup/linux.html"><strong aria-hidden="true">3.1.</strong> Linux</a></li><li class="chapter-item expanded "><a href="03-setup/windows.html"><strong aria-hidden="true">3.2.</strong> Windows</a></li><li class="chapter-item expanded "><a href="03-setup/macos.html"><strong aria-hidden="true">3.3.</strong> macOS</a></li><li class="chapter-item expanded "><a href="03-setup/verify.html"><strong aria-hidden="true">3.4.</strong> Verify the installation</a></li></ol></li><li class="chapter-item expanded "><a href="04-meet-your-hardware/index.html"><strong aria-hidden="true">4.</strong> Meet your hardware</a></li><li class="chapter-item expanded "><a href="05-led-roulette/index.html"><strong aria-hidden="true">5.</strong> LED roulette</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="05-led-roulette/build-it.html"><strong aria-hidden="true">5.1.</strong> Build it</a></li><li class="chapter-item expanded "><a href="05-led-roulette/flash-it.html"><strong aria-hidden="true">5.2.</strong> Flash it</a></li><li class="chapter-item expanded "><a href="05-led-roulette/debug-it.html"><strong aria-hidden="true">5.3.</strong> Debug it</a></li><li class="chapter-item expanded "><a href="05-led-roulette/the-led-and-delay-abstractions.html"><strong aria-hidden="true">5.4.</strong> The led and delay abstractions</a></li><li class="chapter-item expanded "><a href="05-led-roulette/the-challenge.html"><strong aria-hidden="true">5.5.</strong> The challenge</a></li><li class="chapter-item expanded "><a href="05-led-roulette/my-solution.html"><strong aria-hidden="true">5.6.</strong> My solution</a></li></ol></li><li class="chapter-item expanded "><a href="06-hello-world/index.html"><strong aria-hidden="true">6.</strong> Hello, world!</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="06-hello-world/panic.html"><strong aria-hidden="true">6.1.</strong> panic!</a></li></ol></li><li class="chapter-item expanded "><a href="07-registers/index.html"><strong aria-hidden="true">7.</strong> Registers</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="07-registers/rtrm.html"><strong aria-hidden="true">7.1.</strong> RTRM</a></li><li class="chapter-item expanded "><a href="07-registers/optimization.html"><strong aria-hidden="true">7.2.</strong> (mis)Optimization</a></li><li class="chapter-item expanded "><a href="07-registers/bad-address.html"><strong aria-hidden="true">7.3.</strong> 0xBAAAAAAD address</a></li><li class="chapter-item expanded "><a href="07-registers/spooky-action-at-a-distance.html"><strong aria-hidden="true">7.4.</strong> Spooky action at a distance</a></li><li class="chapter-item expanded "><a href="07-registers/type-safe-manipulation.html"><strong aria-hidden="true">7.5.</strong> Type safe manipulation</a></li></ol></li><li class="chapter-item expanded "><a href="08-leds-again/index.html"><strong aria-hidden="true">8.</strong> LEDs, again</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="08-leds-again/power.html"><strong aria-hidden="true">8.1.</strong> Power</a></li><li class="chapter-item expanded "><a href="08-leds-again/configuration.html"><strong aria-hidden="true">8.2.</strong> Configuration</a></li><li class="chapter-item expanded "><a href="08-leds-again/the-solution.html"><strong aria-hidden="true">8.3.</strong> The solution</a></li></ol></li><li class="chapter-item expanded "><a href="09-clocks-and-timers/index.html"><strong aria-hidden="true">9.</strong> Clocks and timers</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="09-clocks-and-timers/for-loop-delays.html"><strong aria-hidden="true">9.1.</strong> for loop delays</a></li><li class="chapter-item expanded "><a href="09-clocks-and-timers/nop.html"><strong aria-hidden="true">9.2.</strong> NOP</a></li><li class="chapter-item expanded "><a href="09-clocks-and-timers/one-shot-timer.html"><strong aria-hidden="true">9.3.</strong> One-shot timer</a></li><li class="chapter-item expanded "><a href="09-clocks-and-timers/initialization.html"><strong aria-hidden="true">9.4.</strong> Initialization</a></li><li class="chapter-item expanded "><a href="09-clocks-and-timers/busy-waiting.html"><strong aria-hidden="true">9.5.</strong> Busy waiting</a></li><li class="chapter-item expanded "><a href="09-clocks-and-timers/putting-it-all-together.html"><strong aria-hidden="true">9.6.</strong> Putting it all together</a></li></ol></li><li class="chapter-item expanded "><a href="10-serial-communication/index.html"><strong aria-hidden="true">10.</strong> Serial communication</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="10-serial-communication/nix-tooling.html"><strong aria-hidden="true">10.1.</strong> *nix tooling</a></li><li class="chapter-item expanded "><a href="10-serial-communication/windows-tooling.html"><strong aria-hidden="true">10.2.</strong> Windows tooling</a></li><li class="chapter-item expanded "><a href="10-serial-communication/loopbacks.html"><strong aria-hidden="true">10.3.</strong> Loopbacks</a></li></ol></li><li class="chapter-item expanded "><a href="11-usart/index.html"><strong aria-hidden="true">11.</strong> USART</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="11-usart/send-a-single-byte.html"><strong aria-hidden="true">11.1.</strong> Send a single byte</a></li><li class="chapter-item expanded "><a href="11-usart/send-a-string.html"><strong aria-hidden="true">11.2.</strong> Send a string</a></li><li class="chapter-item expanded "><a href="11-usart/buffer-overrun.html"><strong aria-hidden="true">11.3.</strong> Buffer overrun</a></li><li class="chapter-item expanded "><a href="11-usart/uprintln.html"><strong aria-hidden="true">11.4.</strong> uprintln!</a></li><li class="chapter-item expanded "><a href="11-usart/receive-a-single-byte.html"><strong aria-hidden="true">11.5.</strong> Receive a single byte</a></li><li class="chapter-item expanded "><a href="11-usart/echo-server.html"><strong aria-hidden="true">11.6.</strong> Echo server</a></li><li class="chapter-item expanded "><a href="11-usart/reverse-a-string.html"><strong aria-hidden="true">11.7.</strong> Reverse a string</a></li><li class="chapter-item expanded "><a href="11-usart/my-solution.html"><strong aria-hidden="true">11.8.</strong> My solution</a></li></ol></li><li class="chapter-item expanded "><a href="12-bluetooth-setup/index.html"><strong aria-hidden="true">12.</strong> Bluetooth setup</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="12-bluetooth-setup/linux.html"><strong aria-hidden="true">12.1.</strong> Linux</a></li><li class="chapter-item expanded "><a href="12-bluetooth-setup/loopback.html"><strong aria-hidden="true">12.2.</strong> Loopback</a></li><li class="chapter-item expanded "><a href="12-bluetooth-setup/at-commands.html"><strong aria-hidden="true">12.3.</strong> AT commands</a></li></ol></li><li class="chapter-item expanded "><a href="13-serial-over-bluetooth/index.html"><strong aria-hidden="true">13.</strong> Serial over Bluetooth</a></li><li class="chapter-item expanded "><a href="14-i2c/index.html"><strong aria-hidden="true">14.</strong> I2C</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="14-i2c/the-general-protocol.html"><strong aria-hidden="true">14.1.</strong> The general protocol</a></li><li class="chapter-item expanded "><a href="14-i2c/lsm303dlhc.html"><strong aria-hidden="true">14.2.</strong> LSM303DLHC</a></li><li class="chapter-item expanded "><a href="14-i2c/read-a-single-register.html"><strong aria-hidden="true">14.3.</strong> Read a single register</a></li><li class="chapter-item expanded "><a href="14-i2c/the-solution.html"><strong aria-hidden="true">14.4.</strong> The solution</a></li><li class="chapter-item expanded "><a href="14-i2c/read-several-registers.html"><strong aria-hidden="true">14.5.</strong> Read several registers</a></li></ol></li><li class="chapter-item expanded "><a href="15-led-compass/index.html"><strong aria-hidden="true">15.</strong> LED compass</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="15-led-compass/take-1.html"><strong aria-hidden="true">15.1.</strong> Take 1</a></li><li class="chapter-item expanded "><a href="15-led-compass/solution-1.html"><strong aria-hidden="true">15.2.</strong> Solution 1</a></li><li class="chapter-item expanded "><a href="15-led-compass/take-2.html"><strong aria-hidden="true">15.3.</strong> Take 2</a></li><li class="chapter-item expanded "><a href="15-led-compass/solution-2.html"><strong aria-hidden="true">15.4.</strong> Solution 2</a></li><li class="chapter-item expanded "><a href="15-led-compass/magnitude.html"><strong aria-hidden="true">15.5.</strong> Magnitude</a></li><li class="chapter-item expanded "><a href="15-led-compass/calibration.html"><strong aria-hidden="true">15.6.</strong> Calibration</a></li></ol></li><li class="chapter-item expanded "><a href="16-punch-o-meter/index.html"><strong aria-hidden="true">16.</strong> Punch-o-meter</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="16-punch-o-meter/gravity-is-up.html"><strong aria-hidden="true">16.1.</strong> Gravity is up?</a></li><li class="chapter-item expanded "><a href="16-punch-o-meter/the-challenge.html"><strong aria-hidden="true">16.2.</strong> The challenge</a></li><li class="chapter-item expanded "><a href="16-punch-o-meter/my-solution.html"><strong aria-hidden="true">16.3.</strong> My solution</a></li></ol></li><li class="chapter-item expanded "><a href="explore.html"><strong aria-hidden="true">17.</strong> What's left for you to explore</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><a href="appendix/1-general-troubleshooting/index.html">General troubleshooting</a></li><li class="chapter-item expanded affix "><a href="appendix/2-how-to-use-gdb/index.html">How to use GDB</a></li><li class="spacer"></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Discovery</h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        <a href="https://github.com/rust-embedded/discovery/" title="Git repository" aria-label="Git repository">
                            <i id="git-repository-button" class="fa fa-github"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="discovery"><a class="header" href="#discovery">Discovery</a></h1>
<blockquote>
<p>Discover the world of microcontrollers through <a href="https://www.rust-lang.org/">Rust</a>!</p>
</blockquote>
<p>This book is an introductory course on microcontroller-based embedded systems that uses Rust as the
teaching language rather than the usual C/C++.</p>
<h2 id="scope"><a class="header" href="#scope">Scope</a></h2>
<p>The following topics will be covered (eventually, I hope):</p>
<ul>
<li>
<p>How to write, build, flash and debug an &quot;embedded&quot; (Rust) program.</p>
</li>
<li>
<p>Functionality (&quot;peripherals&quot;) commonly found in microcontrollers: Digital input and output, Pulse
Width Modulation (PWM), Analog to Digital Converters (ADC), common communication protocols like
Serial, I2C and SPI, etc.</p>
</li>
<li>
<p>Multitasking concepts: cooperative vs preemptive multitasking, interrupts, schedulers, etc.</p>
</li>
<li>
<p>Control systems concepts: sensors, calibration, digital filters, actuators, open loop control,
closed loop control, etc.</p>
</li>
</ul>
<h2 id="approach"><a class="header" href="#approach">Approach</a></h2>
<ul>
<li>
<p>Beginner friendly. No previous experience with microcontrollers or embedded systems is required.</p>
</li>
<li>
<p>Hands on. Plenty of exercises to put the theory into practice. <em>You</em> will be doing most of the
work here.</p>
</li>
<li>
<p>Tool centered. We'll make plenty use of tooling to ease development. &quot;Real&quot; debugging, with GDB,
and logging will be introduced early on. Using LEDs as a debugging mechanism has no place here.</p>
</li>
</ul>
<h2 id="non-goals"><a class="header" href="#non-goals">Non-goals</a></h2>
<p>What's out of scope for this book:</p>
<ul>
<li>
<p>Teaching Rust. There's plenty of material on that topic already. We'll focus on microcontrollers
and embedded systems.</p>
</li>
<li>
<p>Being a comprehensive text about electric circuit theory or electronics. We'll just cover the
minimum required to understand how some devices work.</p>
</li>
<li>
<p>Covering details such as linker scripts and the boot process. For example, we'll use existing tools
to help get your code onto your board, but not go into detail about how those tools work.</p>
</li>
</ul>
<p>Also I don't intend to port this material to other development boards; this book will make exclusive
use of the STM32F3DISCOVERY development board.</p>
<h2 id="reporting-problems"><a class="header" href="#reporting-problems">Reporting problems</a></h2>
<p>The source of this book is in <a href="https://github.com/rust-embedded/discovery">this repository</a>. If you encounter any typo or problem with the code
report it on the <a href="https://github.com/rust-embedded/discovery/issues">issue tracker</a>.</p>
<h2 id="other-embedded-rust-resources"><a class="header" href="#other-embedded-rust-resources">Other embedded Rust resources</a></h2>
<p>This Discovery book is just one of several embedded Rust resources provided by the
<a href="https://github.com/rust-embedded/wg">Embedded Working Group</a>. The full selection can be found at <a href="https://docs.rust-embedded.org">The Embedded Rust Bookshelf</a>. This
includes the list of <a href="https://docs.rust-embedded.org/faq.html">Frequently Asked Questions</a>.</p>
<h2 id="sponsored-by"><a class="header" href="#sponsored-by">Sponsored by</a></h2>
<p align="center">
<a href="http://integer32.com/">
<img style="width: 50%" title="integer 32" src="assets/integer32.svg">
</a>
</p>
<p>Many thanks to <a href="http://integer32.com/">integer 32</a> for sponsoring me to work on this book! Please
give them lots of work (they do Rust consulting!) so they'll have no choice but to hire more
Rustaceans &lt;3.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="background"><a class="header" href="#background">Background</a></h1>
<h2 id="whats-a-microcontroller"><a class="header" href="#whats-a-microcontroller">What's a microcontroller?</a></h2>
<p>A microcontroller is a <em>system</em> on a chip. Whereas your computer is made up of several discrete
components: a processor, RAM sticks, a hard drive, an ethernet port, etc.; a microcontroller
has all those components built into a single &quot;chip&quot; or package. This makes it possible to
build systems with a minimal part count.</p>
<h2 id="what-can-you-do-with-a-microcontroller"><a class="header" href="#what-can-you-do-with-a-microcontroller">What can you do with a microcontroller?</a></h2>
<p>Lots of things! Microcontrollers are the central part of systems known as <em>embedded</em> systems. 
These systems are everywhere but you don't usually notice them. These systems control the brakes
of your car, wash your clothes, print your documents, keep you warm, keep you cool, optimize the 
fuel consumption of your car, etc.</p>
<p>The main trait of these systems is that they operate without user intervention even if they expose a
user interface as a washing machine does; most of their operation is done on their own.</p>
<p>The other common trait of these systems is that they <em>control</em> a process. And for that these systems
usually have one or more sensors and one or more actuators. For example, an HVAC system has several
sensors, thermometers, and humidity sensors spread across some areas, and several actuators as well,
heating elements and fans connected to ducts.</p>
<h2 id="when-should-i-use-a-microcontroller"><a class="header" href="#when-should-i-use-a-microcontroller">When should I use a microcontroller?</a></h2>
<p>All these applications I've mentioned, you can probably implement with a Raspberry Pi, a computer
that runs Linux. Why should I bother with a microcontroller that operates without an OS? Sounds 
like it would be harder to develop a program.</p>
<p>The main reason is cost. A microcontroller is much cheaper than a general-purpose computer. Not only
the microcontroller is cheaper; it also requires many fewer external electrical components to operate.
This makes Printed Circuit Boards (PCBs) smaller and cheaper to design and manufacture.</p>
<p>The other big reason is power consumption. A microcontroller consumes orders of magnitude less power
than a full-blown processor. If your application will run on batteries that makes a huge difference.</p>
<p>And last but not least: (hard) <em>real-time</em> constraints. Some processes require their controllers to
respond to some events within some time interval (e.g. a quadcopter/drone hit by a wind gust). If this
<em>deadline</em> is not met, the process could end in catastrophic failure (e.g. the drone crashes to the
ground). A general-purpose computer running a general-purpose OS has many services running in the 
background. This makes it hard to guarantee the execution of a program within tight time constraints.</p>
<h2 id="when-should-i-not-use-a-microcontroller"><a class="header" href="#when-should-i-not-use-a-microcontroller">When should I <em>not</em> use a microcontroller?</a></h2>
<p>Where heavy computations are involved. To keep their power consumption low, microcontrollers have very 
limited computational resources available to them. For example, some microcontrollers don't even have 
hardware support for floating-point operations. On those devices, performing a simple addition of 
single-precision numbers can take hundreds of CPU cycles.</p>
<h2 id="why-use-rust-and-not-c"><a class="header" href="#why-use-rust-and-not-c">Why use Rust and not C?</a></h2>
<p>Hopefully, I don't need to convince you here as you are probably familiar with the language 
differences between Rust and C. One point I do want to bring up is package management. C lacks an 
official, widely accepted package management solution whereas Rust has Cargo. This makes development 
<em>much</em> easier. And, IMO, easy package management encourages code reuse because libraries can be 
easily integrated into an application which is also a good thing as libraries get more &quot;battle testing&quot;.</p>
<h2 id="why-should-i-not-use-rust"><a class="header" href="#why-should-i-not-use-rust">Why should I not use Rust?</a></h2>
<p>Or why should I prefer C over Rust?</p>
<p>The C ecosystem is way more mature. Off the shelf solution for several problems already exist. If you 
need to control a time-sensitive process, you can grab one of the existing commercial Real-Time Operating 
Systems (RTOS) out there and solve your problem. There are no commercial, production-grade RTOSes in Rust 
yet so you would have to either create one yourself or try one of the ones that are in development.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="hardwareknowledge-requirements"><a class="header" href="#hardwareknowledge-requirements">Hardware/knowledge requirements</a></h1>
<p>The primary knowledge requirement to read this book is to know <em>some</em> Rust. It's
hard for me to quantify <em>some</em> but at least I can tell you that you don't need
to fully grok generics but you do need to know how to <em>use</em> closures. You also
need to be familiar with the idioms of the <a href="https://rust-lang-nursery.github.io/edition-guide/">2018 edition</a>, in particular with
the fact that <code>extern crate</code> is not necessary in the 2018 edition.</p>
<p>Due to the nature of embedded programming, it will also be extremely helpful to
understand how binary and hexadecimal representations of values work, as well
as the use of some bitwise operators. For example, it would be useful to
understand how the following program produces its output.</p>
<pre><pre class="playground"><code class="language-rust">fn main() {
    let a = 0x4000_0000 + 0xa2;

    // Use of the bit shift &quot;&lt;&lt;&quot; operation.
    let b = 1 &lt;&lt; 5;

    // {:X} will format values as hexadecimal
    println!(&quot;{:X}: {:X}&quot;, a, b);
}
</code></pre></pre>
<p>Also, to follow this material you'll need the following hardware:</p>
<p>(Some components are optional but recommended)</p>
<ul>
<li>A <a href="http://www.st.com/en/evaluation-tools/stm32f3discovery.html">STM32F3DISCOVERY</a> board.</li>
</ul>
<p>(You can purchase this board from &quot;big&quot; <a href="http://www.mouser.com/ProductDetail/STMicroelectronics/STM32F3DISCOVERY">electronics</a> <a href="http://www.digikey.com/product-detail/en/stmicroelectronics/STM32F3DISCOVERY/497-13192-ND">suppliers</a> or from <a href="https://www.aliexpress.com/wholesale?SearchText=stm32f3discovery">e-commerce</a>
<a href="http://www.ebay.com/sch/i.html?_nkw=stm32f3discovery">sites</a>)</p>
<p align="center">
<img title="STM32F3DISCOVERY" src="02-requirements/../assets/f3.jpg">
</p>
<ul>
<li>OPTIONAL. A <strong>3.3V</strong> USB &lt;-&gt; Serial module. To elaborate: if you have one of
the latest revisions of the discovery board (which is usually the case given
the first revision was released years ago) then you do <em>not</em> need this module
because the board includes this functionality on-board. If you have an older
revision of the board then you'll need this module for chapters 10 and 11. For
completeness, we'll include instructions for using a Serial module. The book
will use <a href="https://www.sparkfun.com/products/9873">this particular model</a> but you can use any other model as
long as it operates at 3.3V. The CH340G module, which you can buy
from <a href="https://www.aliexpress.com/wholesale?SearchText=CH340G">e-commerce</a> sites works too and it's probably cheaper for you to get.</li>
</ul>
<p align="center">
<img title="A 3.3v USB <-> Serial module" src="../assets/serial.jpg">
</p>
<ul>
<li>OPTIONAL. A HC-05 Bluetooth module (with headers!). A HC-06 would work too.</li>
</ul>
<p>(As with other Chinese parts, you pretty much can only find these on <a href="http://www.ebay.com/sch/i.html?_nkw=hc-05">e-commerce</a> <a href="https://www.aliexpress.com/wholesale?SearchText=hc-05">sites</a>.
(US) Electronics suppliers don't usually stock these for some reason)</p>
<p align="center">
<img title="The HC-05 Bluetooth module" src="02-requirements/../assets/bluetooth.jpg">
</p>
<ul>
<li>Two mini-B USB cables. One is required to make the STM32F3DISCOVERY board work. The other is only
required if you have the Serial &lt;-&gt; USB module. Make sure that the cables both
support data transfer as some cables only support charging devices.</li>
</ul>
<p align="center">
<img title="mini-B USB cable" src="02-requirements/../assets/usb-cable.jpg">
</p>
<blockquote>
<p><strong>NOTE</strong> These are <strong>not</strong> the USB cables that ship with pretty much every Android phone; those
are <em>micro</em> USB cables. Make sure you have the right thing!</p>
</blockquote>
<ul>
<li>MOSTLY OPTIONAL. 5 female to female, 4 male to female and 1 Male to Male <em>jumper</em> (AKA Dupont)
wires. You'll <em>very likely</em> need one female to female to get ITM working. The other wires are only
needed if you'll be using the USB &lt;-&gt; Serial and Bluetooth modules.</li>
</ul>
<p>(You can get these from electronics <a href="https://www.adafruit.com/categories/306">suppliers</a> or from <a href="http://www.ebay.com/sch/i.html?_nkw=dupont+wire">e-commerce</a> <a href="https://www.aliexpress.com/wholesale?SearchText=dupont+wire">sites</a>)</p>
<p align="center">
<img title="Jumper wires" src="02-requirements/../assets/jumper-wires.jpg">
</p>
<blockquote>
<p><strong>FAQ</strong>: Wait, why do I need this specific hardware?</p>
</blockquote>
<p>It makes my life and yours much easier.</p>
<p>The material is much, much more approachable if we don't have to worry about hardware differences.
Trust me on this one.</p>
<blockquote>
<p><strong>FAQ</strong>: Can I follow this material with a different development board?</p>
</blockquote>
<p>Maybe? It depends mainly on two things: your previous experience with microcontrollers and/or
whether there already exists a high level crate, like the <a href="https://docs.rs/f3"><code>f3</code></a>, for your development board
somewhere.</p>
<p>With a different development board, this text would lose most if not all its beginner friendliness
and &quot;easy to follow&quot;-ness, IMO.</p>
<p>If you have a different development board and you don't consider yourself a total beginner, you are
better off starting with the <a href="https://rust-embedded.github.io/cortex-m-quickstart/cortex_m_quickstart/">quickstart</a> project template.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="setting-up-a-development-environment"><a class="header" href="#setting-up-a-development-environment">Setting up a development environment</a></h1>
<p>Dealing with microcontrollers involves several tools as we'll be dealing with an architecture
different than your computer's and we'll have to run and debug programs on a &quot;remote&quot; device.</p>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<p>Tooling is not everything though. Without documentation it is pretty much impossible to work with
microcontrollers.</p>
<p>We'll be referring to all these documents throughout this book:</p>
<p><em>HEADS UP</em> All these links point to PDF files and some of them are hundreds of pages long and
several MBs in size.</p>
<ul>
<li><a href="http://www.st.com/resource/en/user_manual/dm00063382.pdf">STM32F3DISCOVERY User Manual</a></li>
<li><a href="http://www.st.com/resource/en/datasheet/stm32f303vc.pdf">STM32F303VC Datasheet</a></li>
<li><a href="http://www.st.com/resource/en/reference_manual/dm00043574.pdf">STM32F303VC Reference Manual</a></li>
<li><a href="http://www.st.com/resource/en/datasheet/lsm303dlhc.pdf">LSM303DLHC</a> * </li>
<li><a href="https://www.st.com/content/ccc/resource/technical/document/application_note/2c/d9/a7/f8/43/48/48/64/DM00119036.pdf/files/DM00119036.pdf/jcr:content/translations/en.DM00119036.pdf">L3GD20</a> * </li>
</ul>
<p>* <strong>NOTE</strong>: Newer (from around 2020/09) Discovery boards may have a different e-compass and gyroscope (see the user manual). 
As such, much in chapters 14-16 will not work as is. 
Checkout the github issues like <a href="https://github.com/rust-embedded/discovery/issues/274">this</a>. </p>
<h2 id="tools"><a class="header" href="#tools">Tools</a></h2>
<p>We'll use all the tools listed below. Where a minimum version is not specified, any recent version
should work but we have listed the version we have tested.</p>
<ul>
<li>
<p>Rust 1.31 or a newer toolchain. Chapter <a href="03-setup/../11-usart/index.html">USART</a>
requires 1.51 or newer.</p>
</li>
<li>
<p><a href="https://crates.io/crates/itm"><code>itmdump</code></a> &gt;=0.3.1 (<code>cargo install itm</code>). Tested versions: 0.3.1.</p>
</li>
<li>
<p>OpenOCD &gt;=0.8. Tested versions: v0.9.0 and v0.10.0</p>
</li>
<li>
<p><code>arm-none-eabi-gdb</code>. Version 7.12 or newer highly recommended. Tested versions: 7.10, 7.11,
7.12 and 8.1</p>
</li>
<li>
<p><a href="https://github.com/rust-embedded/cargo-binutils"><code>cargo-binutils</code></a>. Version 0.1.4 or newer.</p>
</li>
</ul>
<ul>
<li>
<p><code>minicom</code> on Linux and macOS. Tested version: 2.7. Readers report that <code>picocom</code> also works but
we'll use <code>minicom</code> in this text.</p>
</li>
<li>
<p><code>PuTTY</code> on Windows.</p>
</li>
</ul>
<p>If your computer has Bluetooth functionality and you have the Bluetooth module, you can additionally
install these tools to play with the Bluetooth module. All these are optional:</p>
<ul>
<li>Linux, only if you don't have a Bluetooth manager application like Blueman.
<ul>
<li><code>bluez</code></li>
<li><code>hcitool</code></li>
<li><code>rfcomm</code></li>
<li><code>rfkill</code></li>
</ul>
</li>
</ul>
<p>macOS / OSX / Windows users only need the default bluetooth manager that ships with their OS.</p>
<p>Next, follow OS-agnostic installation instructions for a few of the tools:</p>
<h3 id="rustc--cargo"><a class="header" href="#rustc--cargo"><code>rustc</code> &amp; Cargo</a></h3>
<p>Install rustup by following the instructions at <a href="https://rustup.rs">https://rustup.rs</a>.</p>
<p>If you already have rustup installed double check that you are on the stable
channel and your stable toolchain is up to date. <code>rustc -V</code> should return a date
newer than the one shown below:</p>
<pre><code class="language-console">$ rustc -V
rustc 1.31.0 (abe02cefd 2018-12-04)
</code></pre>
<h3 id="itmdump"><a class="header" href="#itmdump"><code>itmdump</code></a></h3>
<pre><code class="language-console">cargo install itm
</code></pre>
<p>Verify the version is &gt;=0.3.1</p>
<pre><code>$ itmdump -V
itmdump 0.3.1
</code></pre>
<h3 id="cargo-binutils"><a class="header" href="#cargo-binutils"><code>cargo-binutils</code></a></h3>
<p>Install <code>llvm-tools-preview</code></p>
<pre><code class="language-console">rustup component add llvm-tools-preview
</code></pre>
<p>Install <code>cargo-binutils</code></p>
<pre><code>cargo install cargo-binutils
</code></pre>
<h4 id="verify-tools-are-installed"><a class="header" href="#verify-tools-are-installed">Verify tools are installed</a></h4>
<p>Run the following commands at your terminal</p>
<pre><code class="language-console">cargo new test-size
</code></pre>
<pre><code>cd test-size
</code></pre>
<pre><code>cargo run
</code></pre>
<pre><code>cargo size -- --version
</code></pre>
<p>The results should be something like:</p>
<pre><code>~
$ cargo new test-size
     Created binary (application) `test-size` package

~
$ cd test-size

~/test-size (main)
$ cargo run
   Compiling test-size v0.1.0 (~/test-size)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/test-size`
Hello, world!

~/test-size (main)
$ cargo size -- --version
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
LLVM (http://llvm.org/):
  LLVM version 11.0.0-rust-1.50.0-stable
  Optimized build.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver2
</code></pre>
<h3 id="os-specific-instructions"><a class="header" href="#os-specific-instructions">OS specific instructions</a></h3>
<p>Now follow the instructions specific to the OS you are using:</p>
<ul>
<li><a href="03-setup/linux.html">Linux</a></li>
<li><a href="03-setup/windows.html">Windows</a></li>
<li><a href="03-setup/macos.html">macOS</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="linux"><a class="header" href="#linux">Linux</a></h1>
<p>Here are the installation commands for a few Linux distributions.</p>
<h2 id="required-packages"><a class="header" href="#required-packages">REQUIRED packages</a></h2>
<h3 id="ubuntu-1804-or-newer--debian-stretch-or-newer"><a class="header" href="#ubuntu-1804-or-newer--debian-stretch-or-newer">Ubuntu 18.04 or newer / Debian stretch or newer</a></h3>
<blockquote>
<p><strong>NOTE</strong> <code>gdb-multiarch</code> is the GDB command you'll use to debug your ARM
Cortex-M programs</p>
</blockquote>
<!-- Debian stretch -->
<!-- GDB 7.12 -->
<!-- OpenOCD 0.9.0 -->
<!-- Ubuntu 18.04 -->
<!-- GDB 8.1 -->
<!-- OpenOCD 0.10.0 -->
<pre><code class="language-console">sudo apt-get install \
  gdb-multiarch \
  minicom \
  openocd
</code></pre>
<h3 id="ubuntu-1404-and-1604"><a class="header" href="#ubuntu-1404-and-1604">Ubuntu 14.04 and 16.04</a></h3>
<blockquote>
<p><strong>NOTE</strong> <code>arm-none-eabi-gdb</code> is the GDB command you'll use to debug your ARM
Cortex-M programs</p>
</blockquote>
<!-- Ubuntu 14.04 -->
<!-- GDB 7.6 -->
<!-- OpenOCD 0.7.0 -->
<pre><code class="language-console">sudo apt-get install \
  gdb-arm-none-eabi \
  minicom \
  openocd
</code></pre>
<h3 id="fedora-23-or-newer"><a class="header" href="#fedora-23-or-newer">Fedora 23 or newer</a></h3>
<pre><code class="language-console">sudo dnf install \
  minicom \
  openocd \
  gdb
</code></pre>
<h3 id="arch-linux"><a class="header" href="#arch-linux">Arch Linux</a></h3>
<blockquote>
<p><strong>NOTE</strong> <code>arm-none-eabi-gdb</code> is the GDB command you'll use to debug your ARM
Cortex-M programs</p>
</blockquote>
<pre><code class="language-console">sudo pacman -S \
  arm-none-eabi-gdb \
  minicom \
  openocd
</code></pre>
<h3 id="other-distros"><a class="header" href="#other-distros">Other distros</a></h3>
<blockquote>
<p><strong>NOTE</strong> <code>arm-none-eabi-gdb</code> is the GDB command you'll use to debug your ARM
Cortex-M programs</p>
</blockquote>
<p>For distros that don't have packages for <a href="https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads">ARM's pre-built
toolchain</a>,
download the &quot;Linux 64-bit&quot; file and put its <code>bin</code> directory on your path.
Here's one way to do it:</p>
<pre><code class="language-console">mkdir -p ~/local &amp;&amp; cd ~/local
</code></pre>
<pre><code class="language-console">tar xjf /path/to/downloaded/file/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
</code></pre>
<p>Then, use your editor of choice to append to your <code>PATH</code> in the appropriate
shell init file (e.g. <code>~/.zshrc</code> or <code>~/.bashrc</code>):</p>
<pre><code>PATH=$PATH:$HOME/local/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux/bin
</code></pre>
<h2 id="optional-packages"><a class="header" href="#optional-packages">Optional packages</a></h2>
<h3 id="ubuntu--debian"><a class="header" href="#ubuntu--debian">Ubuntu / Debian</a></h3>
<pre><code class="language-console">sudo apt-get install \
  bluez \
  rfkill
</code></pre>
<h3 id="fedora"><a class="header" href="#fedora">Fedora</a></h3>
<pre><code class="language-console">sudo dnf install \
  bluez \
  rfkill
</code></pre>
<h3 id="arch-linux-1"><a class="header" href="#arch-linux-1">Arch Linux</a></h3>
<pre><code class="language-console">sudo pacman -S \
  bluez \
  bluez-utils \
  rfkill
</code></pre>
<h2 id="udev-rules"><a class="header" href="#udev-rules">udev rules</a></h2>
<p>These rules let you use USB devices like the F3 and the Serial module without root privilege, i.e.
<code>sudo</code>.</p>
<p>Create <code>99-openocd.rules</code> in <code>/etc/udev/rules.d</code> using the <code>idVendor</code> and <code>idProduct</code>
from the <code>lsusb</code> output.</p>
<p>For example, connect the STM32F3DISCOVERY to your computer using a USB cable.
Be sure to connect the cable to the &quot;USB ST-LINK&quot; port, the USB port in the
center of the edge of the board.</p>
<p>Execute <code>lsusb</code>:</p>
<pre><code class="language-console">lsusb | grep ST-LINK
</code></pre>
<p>It should result in something like:</p>
<pre><code>$ lsusb | grep ST-LINK
Bus 003 Device 003: ID 0483:374b STMicroelectronics ST-LINK/V2.1
</code></pre>
<p>So the <code>idVendor</code> is <code>0483</code> and <code>idProduct</code> is <code>374b</code>.</p>
<h3 id="create-etcudevrulesd99-openocdrules"><a class="header" href="#create-etcudevrulesd99-openocdrules">Create <code>/etc/udev/rules.d/99-openocd.rules</code>:</a></h3>
<pre><code class="language-console">sudo vi /etc/udev/rules.d/99-openocd.rules
</code></pre>
<p>With the contents:</p>
<pre><code class="language-text"># STM32F3DISCOVERY - ST-LINK/V2.1
ATTRS{idVendor}==&quot;0483&quot;, ATTRS{idProduct}==&quot;374b&quot;, MODE:=&quot;0666&quot;
</code></pre>
<h4 id="for-older-devices-with-optional-usb---ft232-based-serial-module"><a class="header" href="#for-older-devices-with-optional-usb---ft232-based-serial-module">For older devices with OPTIONAL USB &lt;-&gt; FT232 based Serial Module</a></h4>
<p>Create <code>/etc/udev/rules.d/99-ftdi.rules</code>:</p>
<pre><code class="language-console">sudo vi /etc/udev/rules.d/99-openocd.rules
</code></pre>
<p>With the contents:</p>
<pre><code class="language-text"># FT232 - USB &lt;-&gt; Serial Converter
ATTRS{idVendor}==&quot;0403&quot;, ATTRS{idProduct}==&quot;6001&quot;, MODE:=&quot;0666&quot;
</code></pre>
<h3 id="reload-the-udev-rules-with"><a class="header" href="#reload-the-udev-rules-with">Reload the udev rules with:</a></h3>
<pre><code class="language-console">sudo udevadm control --reload-rules
</code></pre>
<p>If you had any board plugged to your computer, unplug them and then plug them in again.</p>
<p>Now, go to the <a href="03-setup/verify.html">next section</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="windows"><a class="header" href="#windows">Windows</a></h1>
<h2 id="arm-none-eabi-gdb"><a class="header" href="#arm-none-eabi-gdb"><code>arm-none-eabi-gdb</code></a></h2>
<p>ARM provides <code>.exe</code> installers for Windows. Grab one from <a href="https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads">here</a>, and follow the instructions.
Just before the installation process finishes tick/select the &quot;Add path to environment variable&quot;
option. Then verify that the tools are in your <code>%PATH%</code>:</p>
<p>Verify gcc is installed:</p>
<pre><code class="language-console">arm-none-eabi-gcc -v
</code></pre>
<p>The results should be something like:</p>
<pre><code>(..)
$ arm-none-eabi-gcc -v
gcc version 5.4.1 20160919 (release) (..)
</code></pre>
<h2 id="openocd"><a class="header" href="#openocd">OpenOCD</a></h2>
<p>There's no official binary release of OpenOCD for Windows but there are unofficial releases
available <a href="https://github.com/xpack-dev-tools/openocd-xpack/releases">here</a>. Grab the 0.10.x zipfile and extract it somewhere in your drive (I
recommend <code>C:\OpenOCD</code> but with the drive letter that makes sense to you) then update your <code>%PATH%</code>
environment variable to include the following path: <code>C:\OpenOCD\bin</code> (or the path that you used
before).</p>
<p>Verify OpenOCD is installed and in your <code>%PATH%</code> with:</p>
<pre><code class="language-console">openocd -v
</code></pre>
<p>The results should be something like:</p>
<pre><code class="language-console">$ openocd -v
Open On-Chip Debugger 0.10.0
(..)
</code></pre>
<h2 id="putty"><a class="header" href="#putty">PuTTY</a></h2>
<p>Download the latest <code>putty.exe</code> from <a href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/download.html">this site</a> and place it somewhere in your <code>%PATH%</code>.</p>
<h2 id="st-link-usb-driver"><a class="header" href="#st-link-usb-driver">ST-LINK USB driver</a></h2>
<p>You'll also need to install <a href="http://www.st.com/en/embedded-software/stsw-link009.html">this USB driver</a> or OpenOCD won't work. Follow the installer
instructions and make sure you install the right (32-bit or 64-bit) version of the driver.</p>
<p>That's all! Go to the <a href="03-setup/verify.html">next section</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="macos"><a class="header" href="#macos">macOS</a></h1>
<p>All the tools can be install using <a href="http://brew.sh/">Homebrew</a>:</p>
<p>Install ArmMbed</p>
<pre><code class="language-console">brew tap ArmMbed/homebrew-formulae
</code></pre>
<p>Install the ARM GCC toolchain</p>
<pre><code class="language-console">brew install arm-none-eabi-gcc
</code></pre>
<p>Install minicom and OpenOCD</p>
<pre><code class="language-console">brew install minicom openocd
</code></pre>
<p>That's all! Go to the <a href="03-setup/verify.html">next section</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="verify-the-installation"><a class="header" href="#verify-the-installation">Verify the installation</a></h1>
<p>Let's verify that all the tools were installed correctly.</p>
<h2 id="linux-only"><a class="header" href="#linux-only">Linux only</a></h2>
<h3 id="verify-permissions"><a class="header" href="#verify-permissions">Verify permissions</a></h3>
<p>Connect the STM32F3DISCOVERY to your computer using an USB cable. Be sure to connect the cable to the &quot;USB ST-LINK&quot;
port, the USB port in the center of the edge of the board.</p>
<p>The STM32F3DISCOVERY should now appear as a USB device (file) in <code>/dev/bus/usb</code>. Let's find out how it got
enumerated:</p>
<pre><code class="language-console">lsusb | grep -i stm
</code></pre>
<p>This should result in:</p>
<pre><code class="language-console">$ lsusb | grep -i stm
Bus 003 Device 004: ID 0483:374b STMicroelectronics ST-LINK/V2.1
$ # ^^^        ^^^
</code></pre>
<p>In my case, the STM32F3DISCOVERY got connected to the bus #3 and got enumerated as the device #4. This means the
file <code>/dev/bus/usb/003/004</code> <em>is</em> the STM32F3DISCOVERY. Let's check its permissions:</p>
<pre><code class="language-console">$ ls -la /dev/bus/usb/003/004
crw-rw-rw-+ 1 root root 189, 259 Feb 28 13:32 /dev/bus/usb/003/00
</code></pre>
<p>The permissions should be <code>crw-rw-rw-</code>. If it's not ... then check your <a href="03-setup/linux.html#udev-rules">udev
rules</a> and try re-loading them with:</p>
<pre><code class="language-console">sudo udevadm control --reload-rules
</code></pre>
<h4 id="for-older-devices-with-optional-usb---ft232-based-serial-module-1"><a class="header" href="#for-older-devices-with-optional-usb---ft232-based-serial-module-1">For older devices with OPTIONAL USB &lt;-&gt; FT232 based Serial Module</a></h4>
<p>Unplug the STM32F3DISCOVERY and plug the Serial module. Now, figure out what's its associated file:</p>
<pre><code class="language-console">$ lsusb | grep -i ft232
Bus 003 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC
</code></pre>
<p>In my case, it's the <code>/dev/bus/usb/003/005</code>. Now, check its permissions:</p>
<pre><code class="language-console">$ ls -l /dev/bus/usb/003/005
crw-rw-rw- 1 root root 189, 21 Sep 13 00:00 /dev/bus/usb/003/005
</code></pre>
<p>As before, the permissions should be <code>crw-rw-rw-</code>.</p>
<h2 id="verify-openocd-connection"><a class="header" href="#verify-openocd-connection">Verify OpenOCD connection</a></h2>
<p>Connect the STM32F3DISCOVERY using the USB cable to the USB port in the
center of edge of the board, the one that's labeled &quot;USB ST-LINK&quot;.</p>
<p>Two <em>red</em> LEDs should turn on right after connecting the USB cable to the board.</p>
<blockquote>
<p><strong>IMPORTANT</strong> There is more than one hardware revision of the STM32F3DISCOVERY board. For older
revisions, you'll need to change the &quot;interface&quot; argument to <code>-f interface/stlink-v2.cfg</code> (note:
no <code>-1</code> at the end). Alternatively, older revisions can use <code>-f board/stm32f3discovery.cfg</code>
instead of <code>-f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg</code>.</p>
</blockquote>
<blockquote>
<p><strong>NOTE</strong> OpenOCD v0.11.0 has deprecated <code>interface/stlink-v2.cfg</code> in favor of
<code>interface/stlink.cfg</code> which supports ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, and
ST-LINK/V3.</p>
</blockquote>
<h3 id="nix"><a class="header" href="#nix">*Nix</a></h3>
<blockquote>
<p><strong>FYI:</strong> The <code>interface</code> directory is typically located in <code>/usr/share/openocd/scripts/</code>,
which is the default location OpenOCD expects these files. If you've installed them
somewhere else use the <code>-s /path/to/scripts/</code> option to specify your install directory.</p>
</blockquote>
<pre><code class="language-console">openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
</code></pre>
<p>or</p>
<pre><code class="language-console">openocd -f interface/stlink.cfg -f target/stm32f3x.cfg
</code></pre>
<h3 id="windows-1"><a class="header" href="#windows-1">Windows</a></h3>
<p>Below the references to <code>C:\OpenOCD</code> is the directory where OpenOCD is installed.</p>
<pre><code class="language-console">openocd -s C:\OpenOCD\share\scripts -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
</code></pre>
<blockquote>
<p><strong>NOTE</strong> cygwin users have reported problems with the -s flag. If you run into
that problem you can add <code>C:\OpenOCD\share\scripts\</code> directory to the parameters.</p>
</blockquote>
<p>cygwin users:</p>
<pre><code class="language-console">openocd -f C:\OpenOCD\share\scripts\interface\stlink-v2-1.cfg -f C:\OpenOCD\share\scripts\target\stm32f3x.cfg
</code></pre>
<h3 id="all"><a class="header" href="#all">All</a></h3>
<p>OpenOCD is a service which forwards debug information from the ITM channel
to a file, <code>itm.txt</code>, as such it runs forever and does <strong>not</strong> return to the
terminal prompt.</p>
<p>The initial output of OpenOCD is something like:</p>
<pre><code class="language-console">Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport &quot;hla_swd&quot;. To override use 'transport select &lt;transport&gt;'.
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 2.915608
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
</code></pre>
<p>(If you don't ... then check the <a href="03-setup/../appendix/1-general-troubleshooting/index.html">general troubleshooting</a> instructions.)</p>
<p>Also, one of the red LEDs, the one closest to the USB port, should start oscillating between red
light and green light.</p>
<p>That's it! It works. You can now use <code>Ctrl-c</code> to stop OpenOCD or close/kill the terminal.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="meet-your-hardware"><a class="header" href="#meet-your-hardware">Meet your hardware</a></h1>
<p>Let's get familiar with the hardware we'll be working with.</p>
<h2 id="stm32f3discovery-the-f3"><a class="header" href="#stm32f3discovery-the-f3">STM32F3DISCOVERY (the &quot;F3&quot;)</a></h2>
<p align="center">
<img title="F3" src="04-meet-your-hardware/../assets/f3.jpg">
</p>
<p>We'll refer to this board as &quot;F3&quot; throughout this book. Here are some of the
many components on the board:</p>
<ul>
<li>A <a href="https://en.wikipedia.org/wiki/Microcontroller">microcontroller</a>.</li>
<li>A number of LEDs, including the eight aligned in a &quot;compass&quot; formation.</li>
<li>Two buttons.</li>
<li>Two USB ports.</li>
<li>An <a href="https://en.wikipedia.org/wiki/Accelerometer">accelerometer</a>.</li>
<li>A <a href="https://en.wikipedia.org/wiki/Magnetometer">magnetometer</a>.</li>
<li>A <a href="https://en.wikipedia.org/wiki/Gyroscope">gyroscope</a>.</li>
</ul>
<p>Of these components, the most important is the microcontroller (sometimes
shortened to &quot;MCU&quot; for &quot;microcontroller unit&quot;), which is the large black square
sitting in the center of your board. The MCU is what runs your code. You might
sometimes read about &quot;programming a board&quot;, when in reality what we are doing
is programming the MCU that is installed on the board.</p>
<h2 id="stm32f303vct6-the-stm32f3"><a class="header" href="#stm32f303vct6-the-stm32f3">STM32F303VCT6 (the &quot;STM32F3&quot;)</a></h2>
<p>Since the MCU is so important, let's take a closer look at the one sitting on our board.</p>
<p>Our MCU is surrounded by 100 tiny metal <strong>pins</strong>. These pins are connected to
<strong>traces</strong>, the little &quot;roads&quot; that act as the wires connecting components
together on the board. The MCU can dynamically alter the electrical properties
of the pins. This works similar to a light switch altering how electrical
current flows through a circuit. By enabling or disabling electrical current to
flow through a specific pin, an LED attached to that pin (via the traces) can
be turned on and off.</p>
<p>Each manufacturer uses a different part numbering scheme, but many will allow
you to determine information about a component simply by looking at the part
number. Looking at our MCU's part number (<code>STM32F303VCT6</code>), the <code>ST</code> at the
front hints to us that this is a part manufactured by <a href="https://st.com/">ST Microelectronics</a>.
Searching through <a href="https://www.st.com/en/microcontrollers-microprocessors/stm32-mainstream-mcus.html">ST's marketing materials</a> we can also learn the following:</p>
<ul>
<li>The <code>M32</code> represents that this is an Arm®-based 32-bit microcontroller.</li>
<li>The <code>F3</code> represents that the MCU is from ST's &quot;STM32F3&quot; series. This is a
series of MCUs based on the Cortex®-M4 processor design.</li>
<li>The remainder of the part number goes into more details about things like
extra features and RAM size, which at this point we're less concerned about.</li>
</ul>
<blockquote>
<h3 id="arm-cortex-m4"><a class="header" href="#arm-cortex-m4">Arm? Cortex-M4?</a></h3>
<p>If our chip is manufactured by ST, then who is Arm? And if our chip is the
STM32F3, what is the Cortex-M4?</p>
<p>You might be surprised to hear that while &quot;Arm-based&quot; chips are quite
popular, the company behind the &quot;Arm&quot; trademark (<a href="https://www.arm.com/">Arm Holdings</a>) doesn't
actually manufacture chips for purchase. Instead, their primary business
model is to just <em>design</em> parts of chips. They will then license those designs to
manufacturers, who will in turn implement the designs (perhaps with some of
their own tweaks) in the form of physical hardware that can then be sold.
Arm's strategy here is different from companies like Intel, which both
designs <em>and</em> manufactures their chips.</p>
<p>Arm licenses a bunch of different designs. Their &quot;Cortex-M&quot; family of designs
are mainly used as the core in microcontrollers. For example, the Cortex-M0
is designed for low cost and low power usage. The Cortex-M7 is higher cost,
but with more features and performance. The core of our STM32F3 is based on
the Cortex-M4, which is in the middle: more features and performance than the
Cortex-M0, but less expensive than the Cortex-M7.</p>
<p>Luckily, you don't need to know too much about different types of processors
or Cortex designs for the sake of this book. However, you are hopefully now a
bit more knowledgeable about the terminology of your device. While you are
working specifically with an STM32F3, you might find yourself reading
documentation and using tools for Cortex-M-based chips, as the STM32F3 is
based on a Cortex-M design.</p>
</blockquote>
<h2 id="the-serial-module"><a class="header" href="#the-serial-module">The Serial module</a></h2>
<p align="center">
<img title="Serial module" src="04-meet-your-hardware/../assets/serial.jpg">
</p>
<p>If you have an older revision of the discovery board, you can use this module to
exchange data between the microcontroller in the F3 and your computer. This module
will be connected to your computer using an USB cable. I won't say more at this
point.</p>
<p>If you have a newer release of the board then you don't need this module. The
ST-LINK will double as a USB&lt;-&gt;serial converter connected to the microcontroller USART1 at pins PC4 and PC5.</p>
<h2 id="the-bluetooth-module"><a class="header" href="#the-bluetooth-module">The Bluetooth module</a></h2>
<p align="center">
<img title="The HC-05 Bluetooth module" src="04-meet-your-hardware/../assets/bluetooth.jpg">
</p>
<p>This module has the exact same purpose as the serial module but it sends the data over Bluetooth
instead of over USB.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="led-roulette"><a class="header" href="#led-roulette">LED roulette</a></h1>
<p>Alright, let's start by building the following application:</p>
<p align="center">
<img src="https://i.imgur.com/0k1r2Lc.gif">
</p>
<p>I'm going to give you a high level API to implement this app but don't worry we'll do low level
stuff later on. The main goal of this chapter is to get familiar with the <em>flashing</em> and debugging
process.</p>
<p>Throughout this text we'll be using the starter code that's in the <a href="https://github.com/rust-embedded/discovery">discovery</a> repository. Make sure
you always have the latest version of the master branch because this website tracks that branch.</p>
<p>The starter code is in the <code>src</code> directory of that repository. Inside that directory there are more
directories named after each chapter of this book. Most of those directories are starter Cargo
projects.</p>
<p>Now, jump into the <code>src/05-led-roulette</code> directory. Check the <code>src/main.rs</code> file:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux5::entry;

#[entry]
fn main() -&gt; ! {
    let _y;
    let x = 42;
    _y = x;

    // infinite loop; just so we don't leave this stack frame
    loop {}
}
</code></pre></pre>
<p>Microcontroller programs are different from standard programs in two aspects: <code>#![no_std]</code> and
<code>#![no_main]</code>.</p>
<p>The <code>no_std</code> attribute says that this program won't use the <code>std</code> crate, which assumes an underlying
OS; the program will instead use the <code>core</code> crate, a subset of <code>std</code> that can run on bare metal
systems (i.e., systems without OS abstractions like files and sockets).</p>
<p>The <code>no_main</code> attribute says that this program won't use the standard <code>main</code> interface, which is
tailored for command line applications that receive arguments. Instead of the standard <code>main</code> we'll
use the <code>entry</code> attribute from the <a href="https://crates.io/crates/cortex-m-rt"><code>cortex-m-rt</code></a> crate to define a custom entry point. In this
program we have named the entry point &quot;main&quot;, but any other name could have been used. The entry
point function must have the signature <code>fn() -&gt; !</code>; this type indicates that the function can't
return – this means that the program never terminates.</p>
<p>If you are a careful observer, you'll also notice there is a <code>.cargo</code> directory in the Cargo project
as well. This directory contains a Cargo configuration file (<code>.cargo/config</code>) that tweaks the
linking process to tailor the memory layout of the program to the requirements of the target device.
This modified linking process is a requirement of the <code>cortex-m-rt</code> crate. You'll also be making
further tweaks to <code>.cargo/config</code> in future sections to make building and debugging easier.</p>
<p>Alright, let's start by building this program.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="build-it"><a class="header" href="#build-it">Build it</a></h1>
<p>The first step is to build our &quot;binary&quot; crate. Because the microcontroller has a different
architecture than your computer we'll have to cross compile. Cross compiling in Rust land is as simple
as passing an extra <code>--target</code> flag to <code>rustc</code>or Cargo. The complicated part is figuring out the
argument of that flag: the <em>name</em> of the target.</p>
<p>The microcontroller in the F3 has a Cortex-M4F processor in it. <code>rustc</code> knows how to cross compile
to the Cortex-M architecture and provides 4 different targets that cover the different processor
families within that architecture:</p>
<ul>
<li><code>thumbv6m-none-eabi</code>, for the Cortex-M0 and Cortex-M1 processors</li>
<li><code>thumbv7m-none-eabi</code>, for the Cortex-M3 processor</li>
<li><code>thumbv7em-none-eabi</code>, for the Cortex-M4 and Cortex-M7 processors</li>
<li><code>thumbv7em-none-eabihf</code>, for the Cortex-M4<strong>F</strong> and Cortex-M7<strong>F</strong> processors</li>
</ul>
<p>For the F3, we'll use the <code>thumbv7em-none-eabihf</code> target. Before cross compiling you have to
download a pre-compiled version of the standard library (a reduced version of it actually) for your
target. That's done using <code>rustup</code>:</p>
<pre><code class="language-console">rustup target add thumbv7em-none-eabihf
</code></pre>
<p>You only need to do the above step once; <code>rustup</code> will re-install a new standard library
(<code>rust-std</code> component) whenever you update your toolchain.</p>
<p>With the <code>rust-std</code> component in place you can now cross compile the program using Cargo.</p>
<blockquote>
<p><strong>NOTE</strong> Make sure you are in the <code>src/05-led-roulette</code> directory
and run <code>cargo build</code> command below to create the executable:</p>
</blockquote>
<pre><code class="language-console">cargo build --target thumbv7em-none-eabihf
</code></pre>
<p>On your console you should see something like:</p>
<pre><code class="language-console">$ cargo build --target thumbv7em-none-eabihf
   Compiling typenum v1.12.0
   Compiling semver-parser v0.7.0
   Compiling version_check v0.9.2
   Compiling nb v1.0.0
   Compiling void v1.0.2
   Compiling autocfg v1.0.1
   Compiling cortex-m v0.7.1
   Compiling proc-macro2 v1.0.24
   Compiling vcell v0.1.3
   Compiling unicode-xid v0.2.1
   Compiling stable_deref_trait v1.2.0
   Compiling syn v1.0.60
   Compiling bitfield v0.13.2
   Compiling cortex-m v0.6.7
   Compiling cortex-m-rt v0.6.13
   Compiling r0 v0.2.2
   Compiling stm32-usbd v0.5.1
   Compiling stm32f3 v0.12.1
   Compiling usb-device v0.2.7
   Compiling cfg-if v1.0.0
   Compiling paste v1.0.4
   Compiling stm32f3-discovery v0.6.0
   Compiling embedded-dma v0.1.2
   Compiling volatile-register v0.2.0
   Compiling nb v0.1.3
   Compiling embedded-hal v0.2.4
   Compiling semver v0.9.0
   Compiling generic-array v0.14.4
   Compiling switch-hal v0.3.2
   Compiling num-traits v0.2.14
   Compiling num-integer v0.1.44
   Compiling rustc_version v0.2.3
   Compiling bare-metal v0.2.5
   Compiling cast v0.2.3
   Compiling quote v1.0.9
   Compiling generic-array v0.13.2
   Compiling generic-array v0.12.3
   Compiling generic-array v0.11.1
   Compiling panic-itm v0.4.2
   Compiling lsm303dlhc v0.2.0
   Compiling as-slice v0.1.4
   Compiling micromath v1.1.0
   Compiling accelerometer v0.12.0
   Compiling chrono v0.4.19
   Compiling aligned v0.3.4
   Compiling rtcc v0.2.0
   Compiling cortex-m-rt-macros v0.1.8
   Compiling stm32f3xx-hal v0.6.1
   Compiling aux5 v0.2.0 (~/embedded-discovery/src/05-led-roulette/auxiliary)
   Compiling led-roulette v0.2.0 (~/embedded-discovery/src/05-led-roulette)
    Finished dev [unoptimized + debuginfo] target(s) in 17.91s
</code></pre>
<blockquote>
<p><strong>NOTE</strong> Be sure to compile this crate <em>without</em> optimizations. The provided Cargo.toml file and build command above will ensure optimizations are off.</p>
</blockquote>
<p>OK, now we have produced an executable. This executable won't blink any LEDs, it's just a simplified version that we will build upon later in the chapter. As a sanity check, let's verify that the produced executable is actually an ARM binary:</p>
<pre><code class="language-console">cargo readobj --target thumbv7em-none-eabihf --bin led-roulette -- --file-header
</code></pre>
<p>The <code>cargo readobj ..</code> above is equivalent to
<code>readelf -h target/thumbv7em-none-eabihf/debug/led-roulette</code>
and should produce something similar to:</p>
<pre><code class="language-console">$ cargo readobj --target thumbv7em-none-eabihf --bin led-roulette -- --file-header
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x8000195
  Start of program headers:          52 (bytes into file)
  Start of section headers:          818328 (bytes into file)
  Flags:                             0x5000400
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         4
  Size of section headers:           40 (bytes)
  Number of section headers:         22
  Section header string table index: 20
</code></pre>
<p>Next, we'll flash the program into our microcontroller.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="flash-it"><a class="header" href="#flash-it">Flash it</a></h1>
<p>Flashing is the process of moving our program into the microcontroller's (persistent) memory. Once
flashed, the microcontroller will execute the flashed program every time it is powered on.</p>
<p>In this case, our <code>led-roulette</code> program will be the <em>only</em> program in the microcontroller memory.
By this I mean that there's nothing else running on the microcontroller: no OS, no &quot;daemon&quot;,
nothing. <code>led-roulette</code> has full control over the device.</p>
<p>Onto the actual flashing. First thing we need to do is launch OpenOCD. We did that in the
previous section but this time we'll run the command inside a temporary directory (<code>/tmp</code> on *nix;
<code>%TEMP%</code> on Windows).</p>
<p>Make sure the F3 is connected to your computer and run the following commands in a <strong>new terminal</strong>.</p>
<h2 id="for-nix--macos"><a class="header" href="#for-nix--macos">For *nix &amp; MacOS:</a></h2>
<pre><code class="language-console">cd /tmp
openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
</code></pre>
<h2 id="for-windows-note-substitute-c-for-the-actual-openocd-path"><a class="header" href="#for-windows-note-substitute-c-for-the-actual-openocd-path">For Windows <strong>Note</strong>: substitute <code>C:</code> for the actual OpenOCD path:</a></h2>
<pre><code>cd %TEMP%
openocd -s C:\share\scripts -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
</code></pre>
<blockquote>
<p><strong>NOTE</strong> Older revisions of the board need to pass slightly different arguments to
<code>openocd</code>. Review <a href="05-led-roulette/../03-setup/verify.html#first-openocd-connection">this section</a> for the details.</p>
</blockquote>
<p>The program will block; leave that terminal open.</p>
<p>Now it's a good time to explain what the <code>openocd</code> command is actually doing.</p>
<p>I mentioned that the STM32F3DISCOVERY (aka F3) actually has two microcontrollers. One of them is used as a
programmer/debugger. The part of the board that's used as a programmer is called ST-LINK (that's what
STMicroelectronics decided to call it). This ST-LINK is connected to the target microcontroller
using a Serial Wire Debug (SWD) interface (this interface is an ARM standard so you'll run into it
when dealing with other Cortex-M based microcontrollers). This SWD interface can be used to flash
and debug a microcontroller. The ST-LINK is connected to the &quot;USB ST-LINK&quot; port and will appear as
a USB device when you connect the F3 to your computer.</p>
<p align="center">
<img height=640 title="On-board ST-LINK" src="05-led-roulette/../assets/st-link.png">
</p>
<p>As for OpenOCD, it's software that provides some services like a <em>GDB server</em> on top of USB
devices that expose a debugging protocol like SWD or JTAG.</p>
<p>Onto the actual command: those <code>.cfg</code> files we are using instruct OpenOCD to look for a ST-LINK USB
device (<code>interface/stlink-v2-1.cfg</code>) and to expect a STM32F3XX microcontroller
(<code>target/stm32f3x.cfg</code>) to be connected to the ST-LINK.</p>
<p>The OpenOCD output looks like this:</p>
<pre><code class="language-console">$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport &quot;hla_swd&quot;. To override use 'transport select &lt;transport&gt;'.
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v37 API v2 SWIM v26 VID 0x0483 PID 0x374B
Info : using stlink api v2
Info : Target voltage: 2.888183
Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
</code></pre>
<p>The &quot;6 breakpoints, 4 watchpoints&quot; part indicates the debugging features the processor has
available.</p>
<p>Leave that <code>openocd</code> process running, and in the previous terminal or a new terminal
<strong>make sure that you are inside the project's <code>src/05-led-roulette/</code> directory</strong>.</p>
<p>I mentioned that OpenOCD provides a GDB server so let's connect to that right now:</p>
<h2 id="execute-gdb"><a class="header" href="#execute-gdb">Execute GDB</a></h2>
<p>First, we need to determine what version of <code>gdb</code> you have that is capable of debugging ARM binaries.</p>
<p>This could be any one of the commands below, try each one:</p>
<pre><code class="language-console">arm-none-eabi-gdb -q -ex &quot;target remote :3333&quot; target/thumbv7em-none-eabihf/debug/led-roulette
</code></pre>
<pre><code class="language-console">gdb-multiarch -q -ex &quot;target remote :3333&quot; target/thumbv7em-none-eabihf/debug/led-roulette
</code></pre>
<pre><code class="language-console">gdb -q -ex &quot;target remote :3333&quot; target/thumbv7em-none-eabihf/debug/led-roulette
</code></pre>
<h3 id="failing-case"><a class="header" href="#failing-case"><strong>Failing case</strong></a></h3>
<p>You can detect a failing case if there is a <code>warning</code> or <code>error</code> after the <code>Remote debugging using :3333</code> line:</p>
<pre><code>$ gdb -q -ex &quot;target remote :3333&quot; target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...
Remote debugging using :3333
warning: Architecture rejected target-supplied description
Truncated register 16 in remote 'g' packet
(gdb)
</code></pre>
<h3 id="successful-case"><a class="header" href="#successful-case"><strong>Successful case</strong></a></h3>
<p>Successful case 1:</p>
<pre><code>$ arm-none-eabi-gdb -q -ex &quot;target remote :3333&quot; target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...
Remote debugging using :3333
cortex_m_rt::Reset () at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:497
497     pub unsafe extern &quot;C&quot; fn Reset() -&gt; ! {
(gdb)
</code></pre>
<p>Successful case 2:</p>
<pre><code>~/embedded-discovery/src/05-led-roulette (master)
$ arm-none-eabi-gdb -q -ex &quot;target remote :3333&quot; target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...
Remote debugging using :3333
0x00000000 in ?? ()
(gdb)
</code></pre>
<p>In both failing and successful cases you should see new output in the <strong>OpenOCD terminal</strong>, something like the following:</p>
<pre><code class="language-diff"> Info : stm32f3x.cpu: hardware has 6 breakpoints, 4 watchpoints
+Info : accepting 'gdb' connection on tcp/3333
+Info : device id = 0x10036422
+Info : flash size = 256kbytes
</code></pre>
<blockquote>
<p><strong>NOTE</strong> If you are getting an error like <code>undefined debug reason 7 - target needs reset</code>, you can try running <code>monitor reset halt</code> as described <a href="https://stackoverflow.com/questions/38994596/reason-7-target-needs-reset-unreliable-debugging-setup">here</a>.</p>
</blockquote>
<p>By default OpenOCD's GDB server listens on TCP port 3333 (localhost). This command is connecting to
that port.</p>
<h2 id="update-cargoconfigtoml"><a class="header" href="#update-cargoconfigtoml">Update ../.cargo/config.toml</a></h2>
<p>Now that you've successfully determined which debugger you need to use
we need to change <code>../.cargo/config.toml</code> so that the <code>cargo run</code> command will succeed.</p>
<blockquote>
<p><strong>NOTE</strong> <code>cargo</code> is the Rust package manager and you can read about it
<a href="https://doc.rust-lang.org/cargo/">here</a>.</p>
</blockquote>
<p>Get back to the terminal prompt and look at <code>../.cargo/config.toml</code>:</p>
<pre><code class="language-console">~/embedded-discovery/src/05-led-roulette
$ cat ../.cargo/config.toml
[target.thumbv7em-none-eabihf]
runner = &quot;arm-none-eabi-gdb -q&quot;
# runner = &quot;gdb-multiarch -q&quot;
# runner = &quot;gdb -q&quot;
rustflags = [
  &quot;-C&quot;, &quot;link-arg=-Tlink.x&quot;,
]

[build]
target = &quot;thumbv7em-none-eabihf&quot;

</code></pre>
<p>Use your favorite editor to edit <code>../.cargo/config.toml</code> so that the
<code>runner</code> line contains the correct name of that debugger:</p>
<pre><code class="language-console">nano ../.cargo/config.toml
</code></pre>
<p>For example, if your debugger was <code>gdb-multiarch</code> then after
editing the <code>git diff</code> should be:</p>
<pre><code class="language-diff">$ git diff ../.cargo/config.toml
diff --git a/src/.cargo/config.toml b/src/.cargo/config.toml
index ddff17f..8512cfe 100644
--- a/src/.cargo/config.toml
+++ b/src/.cargo/config.toml
@@ -1,6 +1,6 @@
 [target.thumbv7em-none-eabihf]
-runner = &quot;arm-none-eabi-gdb -q&quot;
-# runner = &quot;gdb-multiarch -q&quot;
+# runner = &quot;arm-none-eabi-gdb -q&quot;
+runner = &quot;gdb-multiarch -q&quot;
 # runner = &quot;gdb -q&quot;
 rustflags = [
   &quot;-C&quot;, &quot;link-arg=-Tlink.x&quot;,
</code></pre>
<p>Now that you have <code>../.cargo/config.toml</code> setup let's test it using <code>cargo run</code> to
start the debug session.</p>
<blockquote>
<p><strong>NOTE</strong> The <code>--target thumbv7em-none-eabihf</code> defines which architecture
to build and run. In our <code>../.cargo/config.toml</code> file we have
<code>target = &quot;thumbv7em-none-eabihf&quot;</code> so it is actually not necessary
to specify <code>--target</code> we do it here just so you know that parameters on
the command line can be used and they override those in <code>config.toml</code> files.</p>
</blockquote>
<pre><code>cargo run --target thumbv7em-none-eabihf
</code></pre>
<p>Results in:</p>
<pre><code>~/embedded-discovery/src/05-led-roulette
$ cargo run --target thumbv7em-none-eabihf
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...
</code></pre>
<p>Now issue the <code>target remote :3333</code> to connect to the OpenOCD server
and connect to the F3:</p>
<pre><code>(gdb) target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
</code></pre>
<p>Bravo, we will be modifying <code>../.cargo/config.toml</code> in future. <strong>But</strong>, since
this file is shared with all of the chapters those changes should be made with
that in mind. If you want or we need to make changes that only pertain to
a particular chapter then create a <code>.cargo/config.toml</code> local to that chapter
directory.</p>
<h2 id="flash-the-device"><a class="header" href="#flash-the-device">Flash the device</a></h2>
<p>Assuming you have GDB running, if not start it as suggested in the previous section.</p>
<p>Now use the <code>load</code> command in <code>gdb</code> to actually flash the program into the device:</p>
<pre><code>(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x20ec lma 0x8000194
Loading section .rodata, size 0x514 lma 0x8002280
Start address 0x08000194, load size 10132
Transfer rate: 17 KB/sec, 3377 bytes/write.
</code></pre>
<p>You'll also see new output in the OpenOCD terminal, something like:</p>
<pre><code class="language-diff"> Info : flash size = 256kbytes
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+adapter speed: 950 kHz
+target halted due to debug-request, current mode: Thread
+xPSR: 0x01000000 pc: 0x08000194 msp: 0x2000a000
+Info : Unable to match requested speed 8000 kHz, using 4000 kHz
+Info : Unable to match requested speed 8000 kHz, using 4000 kHz
+adapter speed: 4000 kHz
+target halted due to breakpoint, current mode: Thread
+xPSR: 0x61000000 pc: 0x2000003a msp: 0x2000a000
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+Info : Unable to match requested speed 1000 kHz, using 950 kHz
+adapter speed: 950 kHz
+target halted due to debug-request, current mode: Thread
+xPSR: 0x01000000 pc: 0x08000194 msp: 0x2000a000
</code></pre>
<p>Our program is loaded, let's debug it!</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="debug-it"><a class="header" href="#debug-it">Debug it</a></h1>
<p>We are already inside a debugging session so let's debug our program.</p>
<p>After the <code>load</code> command, our program is stopped at its <em>entry point</em>. This is indicated by the
&quot;Start address 0x8000XXX&quot; part of GDB's output. The entry point is the part of a program that a
processor / CPU will execute first.</p>
<p>The starter project I've provided to you has some extra code that runs <em>before</em> the <code>main</code> function.
At this time, we are not interested in that &quot;pre-main&quot; part so let's skip right to the beginning of
the <code>main</code> function. We'll do that using a breakpoint. Issue <code>break main</code> at the <code>(gdb)</code> prompt:</p>
<blockquote>
<p><strong>NOTE</strong> For these GDB commands I generally won't provide a copyable code block
as these are short and it's faster just to type them yourself. In addition most
can be shortend. For instance <code>b</code> for <code>break</code> or <code>s</code> for <code>step</code>, see <a href="https://users.ece.utexas.edu/%7Eadnan/gdb-refcard.pdf">GDB Quick Reference</a>
for more info or use Google to find your others. In addition, you can use tab completion
by typing the first few letters than one tab to complete or two tabs to
see all possible commands.</p>
<blockquote>
<p>Finally, <code>help xxxx</code> where xxxx is the comand will provide short names and other info:</p>
<pre><code>(gdb) help s
step, s
Step program until it reaches a different source line.
Usage: step [N]
Argument N means step N times (or till program stops for another reason).
</code></pre>
</blockquote>
</blockquote>
<pre><code>(gdb) break main
Breakpoint 1 at 0x80001f0: file src/05-led-roulette/src/main.rs, line 7.
Note: automatically using hardware breakpoints for read-only addresses.
</code></pre>
<p>Next issue a <code>continue</code> command:</p>
<pre><code>(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline () at src/05-led-roulette/src/main.rs:7
7       #[entry]
</code></pre>
<p>Breakpoints can be used to stop the normal flow of a program. The <code>continue</code> command will let the
program run freely <em>until</em> it reaches a breakpoint. In this case, until it reaches <code>#[entry]</code>
which is a trampoline to the main function and where <code>break main</code> sets the breakpoint.</p>
<blockquote>
<p><strong>Note</strong> that GDB output says &quot;Breakpoint 1&quot;. Remember that our processor can only use six of these
breakpoints so it's a good idea to pay attention to these messages.</p>
</blockquote>
<p>OK. Since we are stopped at <code>#[entry]</code> and using the <code>disassemble /m</code> we see the code
for entry, which is a trampoline to main. That means it sets up the stack and then
invokes a subroutine call to the <code>main</code> function using an ARM branch and link instruction, <code>bl</code>.</p>
<pre><code>(gdb) disassemble /m
Dump of assembler code for function main:
7       #[entry]
   0x080001ec &lt;+0&gt;:     push    {r7, lr}
   0x080001ee &lt;+2&gt;:     mov     r7, sp
=&gt; 0x080001f0 &lt;+4&gt;:     bl      0x80001f6 &lt;_ZN12led_roulette18__cortex_m_rt_main17he61ef18c060014a5E&gt;
   0x080001f4 &lt;+8&gt;:     udf     #254    ; 0xfe

End of assembler dump.
</code></pre>
<p>Next we need to issue a <code>step</code> GDB command which will advance the program statement
by statement stepping into functions/procedures. So after this first <code>step</code> command we're
inside <code>main</code> and are positioned at the first executable <code>rust</code> statement, line 10, but it is
<strong>not</strong> executed:</p>
<pre><code>(gdb) step
led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:10
10          let x = 42;
</code></pre>
<p>Next we'll issue a second <code>step</code> which executes line 10 and stops at
line <code>11    _y = x;</code>, again line 11 is <strong>not</strong> executed.</p>
<blockquote>
<p><strong>NOTE</strong> We could have pressed enter at the second <code>(gdb) </code> prompt and
it would have reissued the previous statement, <code>step</code>, but for clarity
in this tutorial we'll generally retype the command.</p>
</blockquote>
<pre><code>(gdb) step
11          _y = x;
</code></pre>
<p>As you can see, in this mode, on each <code>step</code> command GDB will print the current statement along
with its line number. As you'll see later in the TUI mode you'll not see the statement
in the command area.</p>
<p>We are now &quot;on&quot; the <code>_y = x</code> statement; that statement hasn't been executed yet. This means that <code>x</code>
is initialized but <code>_y</code> is not. Let's inspect those stack/local variables using the <code>print</code>
command, <code>p</code> for short:</p>
<pre><code>(gdb) print x
$1 = 42
(gdb) p &amp;x
$2 = (*mut i32) 0x20009fe0
(gdb) p _y
$3 = 536870912
(gdb) p &amp;_y
$4 = (*mut i32) 0x20009fe4
</code></pre>
<p>As expected, <code>x</code> contains the value <code>42</code>. <code>_y</code>, however, contains the value <code>536870912</code> (?). This
is because <code>_y</code> has not been initialized yet, it contains some garbage value.</p>
<p>The command <code>print &amp;x</code> prints the address of the variable <code>x</code>. The interesting bit here is that GDB
output shows the type of the reference: <code>*mut i32</code>, a mutable pointer to an <code>i32</code> value. Another
interesting thing is that the addresses of <code>x</code> and <code>_y</code> are very close to each other: their
addresses are just <code>4</code> bytes apart.</p>
<p>Instead of printing the local variables one by one, you can also use the <code>info locals</code> command:</p>
<pre><code>(gdb) info locals
x = 42
_y = 536870912
</code></pre>
<p>OK. With another <code>step</code>, we'll be on top of the <code>loop {}</code> statement:</p>
<pre><code>(gdb) step
14          loop {}
</code></pre>
<p>And <code>_y</code> should now be initialized.</p>
<pre><code>(gdb) print _y
$5 = 42
</code></pre>
<p>If we use <code>step</code> again on top of the <code>loop {}</code> statement, we'll get stuck because the program will
never pass that statement.</p>
<blockquote>
<p><strong>NOTE</strong> If you used the <code>step</code> or any other command by mistake and GDB gets stuck, you can get
it unstuck by hitting <code>Ctrl+C</code>.</p>
</blockquote>
<p>As introduced above the <code>disassemble /m</code> command can be used to disassemble the program around the
line you are currently at. You might also want to <code>set print asm-demangle on</code>
so the names are demangled, this only needs to be done once a debug session. Later
this and other commands will be placed in an initialization file which will simplify
starting a debug session.</p>
<pre><code>(gdb) set print asm-demangle on
(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17h51e7c3daad2af251E:
8       fn main() -&gt; ! {
   0x080001f6 &lt;+0&gt;:     sub     sp, #8
   0x080001f8 &lt;+2&gt;:     movs    r0, #42 ; 0x2a

9           let _y;
10          let x = 42;
   0x080001fa &lt;+4&gt;:     str     r0, [sp, #0]

11          _y = x;
   0x080001fc &lt;+6&gt;:     str     r0, [sp, #4]

12
13          // infinite loop; just so we don't leave this stack frame
14          loop {}
=&gt; 0x080001fe &lt;+8&gt;:     b.n     0x8000200 &lt;led_roulette::__cortex_m_rt_main+10&gt;
   0x08000200 &lt;+10&gt;:    b.n     0x8000200 &lt;led_roulette::__cortex_m_rt_main+10&gt;

End of assembler dump.
</code></pre>
<p>See the fat arrow <code>=&gt;</code> on the left side? It shows the instruction the processor will execute next.</p>
<p>Also, as mentioned above if you were to execute the <code>step</code> command GDB gets stuck because it
is executing a branch instruction to itself and never gets past it. So you need to use
<code>Ctrl+C</code> to regain control. An alternative is to use the <code>stepi</code>(<code>si</code>) GDB command, which steps
one asm instruction, and GDB will print the address <strong>and</strong> line number of the statement
the processor will execute next and it won't get stuck.</p>
<pre><code>(gdb) stepi
0x08000194      14          loop {}

(gdb) si
0x08000194      14          loop {}
</code></pre>
<p>One last trick before we move to something more interesting. Enter the following commands into GDB:</p>
<pre><code>(gdb) monitor reset halt
Unable to match requested speed 1000 kHz, using 950 kHz
Unable to match requested speed 1000 kHz, using 950 kHz
adapter speed: 950 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000194 msp: 0x2000a000

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline () at src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) disassemble /m
Dump of assembler code for function main:
7       #[entry]
   0x080001ec &lt;+0&gt;:     push    {r7, lr}
   0x080001ee &lt;+2&gt;:     mov     r7, sp
=&gt; 0x080001f0 &lt;+4&gt;:     bl      0x80001f6 &lt;led_roulette::__cortex_m_rt_main&gt;
   0x080001f4 &lt;+8&gt;:     udf     #254    ; 0xfe

End of assembler dump.
</code></pre>
<p>We are now back at the beginning of <code>#[entry]</code>!</p>
<p><code>monitor reset halt</code> will reset the microcontroller and stop it right at the beginning of the program.
The <code>continue</code> command will then let the program run freely until it reaches a breakpoint, in
this case it is the breakpoint at <code>#[entry]</code>.</p>
<p>This combo is handy when you, by mistake, skipped over a part of the program that you were
interested in inspecting. You can easily roll back the state of your program back to its very
beginning.</p>
<blockquote>
<p><strong>The fine print</strong>: This <code>reset</code> command doesn't clear or touch RAM. That memory will retain its
values from the previous run. That shouldn't be a problem though, unless your program behavior
depends of the value of <em>uninitialized</em> variables but that's the definition of Undefined Behavior
(UB).</p>
</blockquote>
<p>We are done with this debug session. You can end it with the <code>quit</code> command.</p>
<pre><code>(gdb) quit
A debugging session is active.

        Inferior 1 [Remote target] will be detached.

Quit anyway? (y or n) y
Detaching from program: $PWD/target/thumbv7em-none-eabihf/debug/led-roulette, Remote target
Ending remote debugging.
</code></pre>
<p>For a nicer debugging experience, you can use GDB's Text User Interface (TUI). To enter into that
mode enter one of the following commands in the GDB shell:</p>
<pre><code>(gdb) layout src
(gdb) layout asm
(gdb) layout split
</code></pre>
<blockquote>
<p><strong>NOTE</strong> Apologies to Windows users, the GDB shipped with the GNU ARM Embedded Toolchain
may not support this TUI mode <code>:-(</code>.</p>
</blockquote>
<p>Below is an example of setting up for a <code>layout split</code> by executing the follow commands.
As you can see we've dropped passing the <code>--target</code> parameter:</p>
<pre><code class="language-console">$ cargo run
(gdb) target remote :3333
(gdb) load
(gdb) set print asm-demangle on
(gdb) set style sources off
(gdb) break main
(gdb) continue
</code></pre>
<p>Here is a command line with the above commands as <code>-ex</code> parameters to save you some typing,
shortly we'll be providing an easier way to execute the initial set of commands:</p>
<pre><code>cargo run -- -q -ex 'target remote :3333' -ex 'load' -ex 'set print asm-demangle on' -ex 'set style sources off' -ex 'b main' -ex 'c' target/thumbv7em-none-eabihf/debug/led-roulette
</code></pre>
<p>And below is the result:</p>
<p><img src="05-led-roulette/../assets/gdb-layout-split-1.png" alt="GDB session layout split" title="GDB TUI layout split 1" /></p>
<p>Now we'll scroll the top source window down so we see the entire file and execute <code>layout split</code> and then <code>step</code>:</p>
<p><img src="05-led-roulette/../assets/gdb-layout-split-2.png" alt="GDB session layout split" title="GDB TUI layout split 2" /></p>
<p>Then we'll execute a few <code>info locals</code> and <code>step</code>'s:</p>
<pre><code class="language-console">(gdb) info locals
(gdb) step
(gdb) info locals
(gdb) step
(gdb) info locals
</code></pre>
<p><img src="05-led-roulette/../assets/gdb-layout-split-3.png" alt="GDB session layout split" title="GDB TUI layout split 3" /></p>
<p>At any point you can leave the TUI mode using the following command:</p>
<pre><code>(gdb) tui disable
</code></pre>
<p><img src="05-led-roulette/../assets/gdb-layout-split-4.png" alt="GDB session layout split" title="GDB TUI layout split 4" /></p>
<blockquote>
<p><strong>NOTE</strong> If the default GDB CLI is not to your liking check out <a href="https://github.com/cyrus-and/gdb-dashboard#gdb-dashboard">gdb-dashboard</a>. It uses Python to
turn the default GDB CLI into a dashboard that shows registers, the source view, the assembly view
and other things.</p>
</blockquote>
<p>Don't close OpenOCD though! We'll use it again and again later on. It's better
just to leave it running. If you want to learn more about what GDB can do, check out the section <a href="05-led-roulette/../appendix/2-how-to-use-gdb/">How to use GDB</a>.</p>
<p>What's next? The high level API I promised.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="the-led-and-delay-abstractions"><a class="header" href="#the-led-and-delay-abstractions">The <code>Led</code> and <code>Delay</code> abstractions</a></h1>
<p>Now, I'm going to introduce two high level abstractions that we'll use to implement the LED roulette
application.</p>
<p>The auxiliary crate, <code>aux5</code>, exposes an initialization function called <code>init</code>. When called this
function returns two values packed in a tuple: a <code>Delay</code> value and a <code>LedArray</code> value.</p>
<p><code>Delay</code> can be used to block your program for a specified amount of milliseconds.</p>
<p><code>LedArray</code> is an array of eight <code>Led</code>s. Each <code>Led</code> represents one of the LEDs on the F3 board,
and exposes two methods: <code>on</code> and <code>off</code> which can be used to turn the LED on or off, respectively.</p>
<p>Let's try out these two abstractions by modifying the starter code to look like this:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux5::{entry, Delay, DelayMs, LedArray, OutputSwitch};

#[entry]
fn main() -&gt; ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let half_period = 500_u16;

    loop {
        leds[0].on().ok();
        delay.delay_ms(half_period);

        leds[0].off().ok();
        delay.delay_ms(half_period);
    }
}
</code></pre></pre>
<p>Now build it:</p>
<pre><code class="language-console">cargo build
</code></pre>
<blockquote>
<p><strong>NOTE</strong> It's possible to forget to rebuild the program <em>before</em> starting a GDB session; this
omission can lead to very confusing debug sessions. To avoid this problem you can call just <code>cargo run</code>
instead of <code>cargo build</code>; <code>cargo run</code>. The <code>cargo run</code> command will build <em>and</em> start a debug
session ensuring you never forget to recompile your program.</p>
</blockquote>
<p>Now we'll run and repeat the flashing procedure as we did in the previous section
but with the new program. I'll let you type in the <code>cargo run</code>, <em>this will get easier shortly</em>. :)
Note: </p>
<p>Don't forget to start <code>openocd</code> (debugger) on a separate terminal. Otherwise <code>target remote :3333</code> won't work! </p>
<pre><code class="language-console">$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...

(gdb) target remote :3333
Remote debugging using :3333
led_roulette::__cortex_m_rt_main_trampoline () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x52c0 lma 0x8000194
Loading section .rodata, size 0xb50 lma 0x8005454
Start address 0x08000194, load size 24484
Transfer rate: 21 KB/sec, 6121 bytes/write.

(gdb) break main
Breakpoint 1 at 0x8000202: file ~/embedded-discovery/src/05-led-roulette/src/main.rs, line 7.
Note: automatically using hardware breakpoints for read-only addresses.

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline ()
    at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) step
led_roulette::__cortex_m_rt_main () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:9
9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

(gdb)
</code></pre>
<p>OK. Let's step through the code. This time, we'll use the <code>next</code> command instead of <code>step</code>. The
difference is that the <code>next</code> command will step <em>over</em> function calls instead of going inside them.</p>
<pre><code>(gdb) next
11          let half_period = 500_u16;

(gdb) next
13          loop {

(gdb) next
14              leds[0].on().ok();

(gdb) next
15              delay.delay_ms(half_period);
</code></pre>
<p>After executing the <code>leds[0].on().ok()</code> statement, you should see a red LED, the one pointing North,
turn on.</p>
<p>Let's continue stepping over the program:</p>
<pre><code>(gdb) next
17              leds[0].off().ok();

(gdb) next
18              delay.delay_ms(half_period);
</code></pre>
<p>The <code>delay_ms</code> call will block the program for half a second but you may not notice because the
<code>next</code> command also takes some time to execute. However, after stepping over the <code>leds[0].off()</code>
statement you should see the red LED turn off.</p>
<p>You can already guess what this program does. Let it run uninterrupted using the <code>continue</code> command.</p>
<pre><code>(gdb) continue
Continuing.
</code></pre>
<p>Now, let's do something more interesting. We are going to modify the behavior of our program using
GDB.</p>
<p>First, let's stop the infinite loop by hitting <code>Ctrl+C</code>. You'll probably end up somewhere inside
<code>Led::on</code>, <code>Led::off</code> or <code>delay_ms</code>:</p>
<pre><code>^C
Program received signal SIGINT, Interrupt.
0x08003434 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
</code></pre>
<p>In my case, the program stopped its execution inside a <code>read_volatile</code> function. GDB output shows
some interesting information about that: <code>core::ptr::read_volatile (src=0xe000e010)</code>. This means
that the function comes from the <code>core</code> crate and that it was called with argument <code>src = 0xe000e010</code>.</p>
<p>Just so you know, a more explicit way to show the arguments of a function is to use the <code>info args</code>
command:</p>
<pre><code>(gdb) info args
src = 0xe000e010
</code></pre>
<p>Regardless of where your program may have stopped you can always look at the output of the
<code>backtrace</code> command (<code>bt</code> for short) to learn how it got there:</p>
<pre><code>(gdb) backtrace
#0  0x08003434 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
#1  0x08002d66 in vcell::VolatileCell&lt;u32&gt;::get&lt;u32&gt; (self=0xe000e010) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/vcell-0.1.3/src/lib.rs:33
#2  volatile_register::RW&lt;u32&gt;::read&lt;u32&gt; (self=0xe000e010) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/volatile-register-0.2.0/src/lib.rs:75
#3  cortex_m::peripheral::SYST::has_wrapped (self=0x20009fa4)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/peripheral/syst.rs:136
#4  0x08003004 in stm32f3xx_hal::delay::{{impl}}::delay_us (self=0x20009fa4, us=500000)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:58
#5  0x08002f3e in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:32
#6  0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
#7  0x0800024c in led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:15
#8  0x08000206 in led_roulette::__cortex_m_rt_main_trampoline () at src/05-led-roulette/src/main.rs:7
</code></pre>
<p><code>backtrace</code> will print a trace of function calls from the current function down to main.</p>
<p>Back to our topic. To do what we are after, first, we have to return to the <code>main</code> function. We can
do that using the <code>finish</code> command. This command resumes the program execution and stops it again
right after the program returns from the current function. We'll have to call it several times.</p>
<pre><code>(gdb) finish
Run till exit from #0  0x08003434 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
cortex_m::peripheral::SYST::has_wrapped (self=0x20009fa4)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/peripheral/syst.rs:136
136             self.csr.read() &amp; SYST_CSR_COUNTFLAG != 0
Value returned is $1 = 5

(..)

(gdb) finish
Run till exit from #0  0x08002f3e in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:32
0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
38              self.delay_ms(u32(ms));

(gdb) finish
Run till exit from #0  0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
0x0800024c in led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:15
15              delay.delay_ms(half_period);
</code></pre>
<p>We are back in <code>main</code>. We have a local variable in here: <code>half_period</code></p>
<pre><code>(gdb) print half_period
$3 = 500
</code></pre>
<p>Now, we are going to modify this variable using the <code>set</code> command:</p>
<pre><code>(gdb) set half_period = 100

(gdb) print half_period
$5 = 100
</code></pre>
<p>If you let program run free again using the <code>continue</code> command, you <strong>might</strong> see that the LED will
blink at a much faster rate now, but more likely the blink rate didn't change. <strong>What happened?</strong></p>
<p>Let's stop the program with <code>Ctrl+C</code> and then set a break point at <code>main:14</code>.</p>
<pre><code class="language-console">(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
core::cell::UnsafeCell&lt;u32&gt;::get&lt;u32&gt; (self=0x20009fa4)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1711
1711        pub const fn get(&amp;self) -&gt; *mut T {
</code></pre>
<p>Then set a break point at <code>main.rs:14</code> and <code>continue</code></p>
<pre><code class="language-console">(gdb) break main.rs:14
Breakpoint 2 at 0x8000236: file src/05-led-roulette/src/main.rs, line 14.
(gdb) continue
Continuing.

Breakpoint 2, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:14
14              leds[0].on().ok();
</code></pre>
<p>Now open your terminal window so it's about 80 lines long an 170 characters wide if possible.</p>
<blockquote>
<p><strong>NOTE</strong> If you can't open the terminal that large, no problem you'll just see
<code>--Type &lt;RET&gt; for more, q to quit, c to continue without paging--</code> so just type return
until you see the <code>(gdb)</code> prompt. Then scroll your terminal window to
see the results.</p>
</blockquote>
<pre><code class="language-console">(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17h51e7c3daad2af251E:
8       fn main() -&gt; ! {
   0x08000208 &lt;+0&gt;:     push    {r7, lr}
   0x0800020a &lt;+2&gt;:     mov     r7, sp
   0x0800020c &lt;+4&gt;:     sub     sp, #64 ; 0x40
   0x0800020e &lt;+6&gt;:     add     r0, sp, #32

9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
   0x08000210 &lt;+8&gt;:     bl      0x8000302 &lt;aux5::init&gt;
   0x08000214 &lt;+12&gt;:    b.n     0x8000216 &lt;led_roulette::__cortex_m_rt_main+14&gt;
   0x08000216 &lt;+14&gt;:    add     r0, sp, #32
   0x08000218 &lt;+16&gt;:    add     r1, sp, #4
   0x0800021a &lt;+18&gt;:    ldmia.w r0, {r2, r3, r4, r12, lr}
   0x0800021e &lt;+22&gt;:    stmia.w r1, {r2, r3, r4, r12, lr}
   0x08000222 &lt;+26&gt;:    ldr     r0, [sp, #52]   ; 0x34
   0x08000224 &lt;+28&gt;:    ldr     r1, [sp, #56]   ; 0x38
   0x08000226 &lt;+30&gt;:    str     r1, [sp, #28]
   0x08000228 &lt;+32&gt;:    str     r0, [sp, #24]
   0x0800022a &lt;+34&gt;:    mov.w   r0, #500        ; 0x1f4

10
11          let half_period = 500_u16;
   0x0800022e &lt;+38&gt;:    strh.w  r0, [r7, #-2]

12
13          loop {
   0x08000232 &lt;+42&gt;:    b.n     0x8000234 &lt;led_roulette::__cortex_m_rt_main+44&gt;
   0x08000234 &lt;+44&gt;:    add     r0, sp, #24
   0x08000268 &lt;+96&gt;:    b.n     0x8000234 &lt;led_roulette::__cortex_m_rt_main+44&gt;

14              leds[0].on().ok();
=&gt; 0x08000236 &lt;+46&gt;:    bl      0x80001ec &lt;switch_hal::output::{{impl}}::on&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x0800023a &lt;+50&gt;:    b.n     0x800023c &lt;led_roulette::__cortex_m_rt_main+52&gt;
   0x0800023c &lt;+52&gt;:    bl      0x8000594 &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x08000240 &lt;+56&gt;:    b.n     0x8000242 &lt;led_roulette::__cortex_m_rt_main+58&gt;
   0x08000242 &lt;+58&gt;:    add     r0, sp, #4
   0x08000244 &lt;+60&gt;:    mov.w   r1, #500        ; 0x1f4

15              delay.delay_ms(half_period);
   0x08000248 &lt;+64&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x0800024c &lt;+68&gt;:    b.n     0x800024e &lt;led_roulette::__cortex_m_rt_main+70&gt;
   0x0800024e &lt;+70&gt;:    add     r0, sp, #24

16
17              leds[0].off().ok();
   0x08000250 &lt;+72&gt;:    bl      0x800081a &lt;switch_hal::output::{{impl}}::off&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x08000254 &lt;+76&gt;:    b.n     0x8000256 &lt;led_roulette::__cortex_m_rt_main+78&gt;
   0x08000256 &lt;+78&gt;:    bl      0x8000594 &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x0800025a &lt;+82&gt;:    b.n     0x800025c &lt;led_roulette::__cortex_m_rt_main+84&gt;
   0x0800025c &lt;+84&gt;:    add     r0, sp, #4
   0x0800025e &lt;+86&gt;:    mov.w   r1, #500        ; 0x1f4

18              delay.delay_ms(half_period);
   0x08000262 &lt;+90&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x08000266 &lt;+94&gt;:    b.n     0x8000268 &lt;led_roulette::__cortex_m_rt_main+96&gt;

End of assembler dump.
</code></pre>
<p>In the above dump the reason the delay didn't change was because the compiler
recognized that half_period didn't change and instead in the two places where
<code>delay.delay_ms(half_period);</code> is called we see <code>mov.w r1, #500</code>. So changing the
value of <code>half_period</code> does nothing!</p>
<pre><code class="language-console">   0x08000244 &lt;+60&gt;:    mov.w   r1, #500        ; 0x1f4

15              delay.delay_ms(half_period);
   0x08000248 &lt;+64&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;

(..)

   0x0800025e &lt;+86&gt;:    mov.w   r1, #500        ; 0x1f4

18              delay.delay_ms(half_period);
   0x08000262 &lt;+90&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
</code></pre>
<p>One solution to the problem is to wrap <code>half_period</code> in a <code>Volatile</code> as shown below.</p>
<pre><code class="language-console">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use volatile::Volatile;
use aux5::{Delay, DelayMs, LedArray, OutputSwitch, entry};

#[entry]
fn main() -&gt; ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let mut half_period = 500_u16;
    let v_half_period = Volatile::new(&amp;mut half_period);

    loop {
        leds[0].on().ok();
        delay.delay_ms(v_half_period.read());

        leds[0].off().ok();
        delay.delay_ms(v_half_period.read());
    }
}

</code></pre>
<p>Edit <code>Cargo.toml</code> adding <code>volatile = &quot;0.4.3&quot;</code> in the <code>[dependencies]</code> section.</p>
<pre><code class="language-console">[dependencies]
aux5 = { path = &quot;auxiliary&quot; }
volatile = &quot;0.4.3&quot;
</code></pre>
<p>With the above code using <code>Volatile</code> you can now change <code>half_period</code> and
you'll be able to experiment with different values. Here is the list of
commands followed by an explanation; <code># xxxx</code> to demonstrate.</p>
<pre><code>$ cargo run --target thumbv7em-none-eabihf   # Compile and load the program into gdb
(gdb) target remote :3333           # Connect to STM32F3DISCOVERY board from PC
(gdb) load                          # Flash program
(gdb) break main.rs:16              # Set breakpoint 1 at top of loop
(gdb) continue                      # Continue, will stop at main.rs:16
(gdb) disable 1                     # Disable breakpoint 1
(gdb) set print asm-demangle on     # Enable asm-demangle
(gdb) disassemble /m                # Disassemble main function
(gdb) continue                      # Led blinking on for 1/2 sec then off 1/2 sec
^C                                  # Stop with Ctrl+C
(gdb) enable 1                      # Enable breakpiont 1
(gdb) continue                      # Continue, will stop at main.rs:16
(gdb) print half_period             # Print half_period result is 500
(gdb) set half_period = 2000        # Set half_period to 2000ms
(gdb) print half_period             # Print half_period and result is 2000
(gdb) disable 1                     # Disable breakpoint 1
(gdb) continue                      # Led blinking on for 2 secs then off 2 sec
^C                                  # Stop with Ctrl+C
(gdb) quit                          # Quit gdb
</code></pre>
<p>The critical changes are at lines 13, 17 and 20 in the source code which
you can see in the disassembly. At 13 we creating <code>v_half_period</code> and then
<code>read()</code> it's value in lines 17 and 20. This means that when we <code>set half_period = 2000</code>
the led will now be on for 2 seconds then off for 2 seconds.</p>
<pre><code class="language-console">$ cargo run --target thumbv7em-none-eabihf
   Compiling led-roulette v0.2.0 (~/embedded-discovery/src/05-led-roulette)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...

(gdb) target remote :3333
Remote debugging using :3333
led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x5258 lma 0x8000194
Loading section .rodata, size 0xbd8 lma 0x80053ec
Start address 0x08000194, load size 24516
Transfer rate: 21 KB/sec, 6129 bytes/write.

(gdb) break main.rs:16
Breakpoint 1 at 0x8000246: file src/05-led-roulette/src/main.rs, line 16.
Note: automatically using hardware breakpoints for read-only addresses.

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) disable 1

(gdb) set print asm-demangle on

(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17he1f2bc7990b13731E:
9       fn main() -&gt; ! {
   0x0800020e &lt;+0&gt;:     push    {r7, lr}
   0x08000210 &lt;+2&gt;:     mov     r7, sp
   0x08000212 &lt;+4&gt;:     sub     sp, #72 ; 0x48
   0x08000214 &lt;+6&gt;:     add     r0, sp, #36     ; 0x24

10          let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
   0x08000216 &lt;+8&gt;:     bl      0x800036a &lt;aux5::init&gt;
   0x0800021a &lt;+12&gt;:    b.n     0x800021c &lt;led_roulette::__cortex_m_rt_main+14&gt;
   0x0800021c &lt;+14&gt;:    add     r0, sp, #36     ; 0x24
   0x0800021e &lt;+16&gt;:    add     r1, sp, #8
   0x08000220 &lt;+18&gt;:    ldmia.w r0, {r2, r3, r4, r12, lr}
   0x08000224 &lt;+22&gt;:    stmia.w r1, {r2, r3, r4, r12, lr}
   0x08000228 &lt;+26&gt;:    ldr     r0, [sp, #56]   ; 0x38
   0x0800022a &lt;+28&gt;:    ldr     r1, [sp, #60]   ; 0x3c
   0x0800022c &lt;+30&gt;:    str     r1, [sp, #32]
   0x0800022e &lt;+32&gt;:    str     r0, [sp, #28]
   0x08000230 &lt;+34&gt;:    mov.w   r0, #500        ; 0x1f4

11
12          let mut half_period = 500_u16;
   0x08000234 &lt;+38&gt;:    strh.w  r0, [r7, #-6]
   0x08000238 &lt;+42&gt;:    subs    r0, r7, #6

13          let v_half_period = Volatile::new(&amp;mut half_period);
   0x0800023a &lt;+44&gt;:    bl      0x800033e &lt;volatile::Volatile&lt;&amp;mut u16, volatile::access::ReadWrite&gt;::new&lt;&amp;mut u16&gt;&gt;
   0x0800023e &lt;+48&gt;:    str     r0, [sp, #68]   ; 0x44
   0x08000240 &lt;+50&gt;:    b.n     0x8000242 &lt;led_roulette::__cortex_m_rt_main+52&gt;

14
15          loop {
   0x08000242 &lt;+52&gt;:    b.n     0x8000244 &lt;led_roulette::__cortex_m_rt_main+54&gt;
   0x08000244 &lt;+54&gt;:    add     r0, sp, #28
   0x08000288 &lt;+122&gt;:   b.n     0x8000244 &lt;led_roulette::__cortex_m_rt_main+54&gt;

16              leds[0].on().ok();
=&gt; 0x08000246 &lt;+56&gt;:    bl      0x800032c &lt;switch_hal::output::{{impl}}::on&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x0800024a &lt;+60&gt;:    b.n     0x800024c &lt;led_roulette::__cortex_m_rt_main+62&gt;
   0x0800024c &lt;+62&gt;:    bl      0x80005fc &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x08000250 &lt;+66&gt;:    b.n     0x8000252 &lt;led_roulette::__cortex_m_rt_main+68&gt;
   0x08000252 &lt;+68&gt;:    add     r0, sp, #68     ; 0x44

17              delay.delay_ms(v_half_period.read());
   0x08000254 &lt;+70&gt;:    bl      0x800034a &lt;volatile::Volatile&lt;&amp;mut u16, volatile::access::ReadWrite&gt;::read&lt;&amp;mut u16,u16,volatile::access::ReadWrite&gt;&gt;
   0x08000258 &lt;+74&gt;:    str     r0, [sp, #4]
   0x0800025a &lt;+76&gt;:    b.n     0x800025c &lt;led_roulette::__cortex_m_rt_main+78&gt;
   0x0800025c &lt;+78&gt;:    add     r0, sp, #8
   0x0800025e &lt;+80&gt;:    ldr     r1, [sp, #4]
   0x08000260 &lt;+82&gt;:    bl      0x8002fc4 &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x08000264 &lt;+86&gt;:    b.n     0x8000266 &lt;led_roulette::__cortex_m_rt_main+88&gt;
   0x08000266 &lt;+88&gt;:    add     r0, sp, #28

18
19              leds[0].off().ok();
   0x08000268 &lt;+90&gt;:    bl      0x8000882 &lt;switch_hal::output::{{impl}}::off&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x0800026c &lt;+94&gt;:    b.n     0x800026e &lt;led_roulette::__cortex_m_rt_main+96&gt;
   0x0800026e &lt;+96&gt;:    bl      0x80005fc &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x08000272 &lt;+100&gt;:   b.n     0x8000274 &lt;led_roulette::__cortex_m_rt_main+102&gt;
   0x08000274 &lt;+102&gt;:   add     r0, sp, #68     ; 0x44

20              delay.delay_ms(v_half_period.read());
   0x08000276 &lt;+104&gt;:   bl      0x800034a &lt;volatile::Volatile&lt;&amp;mut u16, volatile::access::ReadWrite&gt;::read&lt;&amp;mut u16,u16,volatile::access::ReadWrite&gt;&gt;
   0x0800027a &lt;+108&gt;:   str     r0, [sp, #0]
   0x0800027c &lt;+110&gt;:   b.n     0x800027e &lt;led_roulette::__cortex_m_rt_main+112&gt;
   0x0800027e &lt;+112&gt;:   add     r0, sp, #8
   0x08000280 &lt;+114&gt;:   ldr     r1, [sp, #0]
   0x08000282 &lt;+116&gt;:   bl      0x8002fc4 &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x08000286 &lt;+120&gt;:   b.n     0x8000288 &lt;led_roulette::__cortex_m_rt_main+122&gt;

End of assembler dump.

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x080037b2 in core::cell::UnsafeCell&lt;u32&gt;::get&lt;u32&gt; (self=0x20009fa0) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1716
1716        }

(gdb) enable 1

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) print half_period
$2 = 500

(gdb) disable 1

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x08003498 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1052
1052        unsafe { intrinsics::volatile_load(src) }

(gdb) enable 1

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) print half_period
$3 = 500

(gdb) set half_period = 2000

(gdb) print half_period
$4 = 2000

(gdb) disable 1

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x0800348e in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1046
1046    pub unsafe fn read_volatile&lt;T&gt;(src: *const T) -&gt; T {

(gdb) q
Detaching from program: ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette, Remote target
Ending remote debugging.
[Inferior 1 (Remote target) detached]
</code></pre>
<p>Question! What happens if you start lowering the value of <code>half_period</code>? At what value of
<code>half_period</code> you can no longer see the LED blink?</p>
<p>Now, it's your turn to write a program.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="the-challenge"><a class="header" href="#the-challenge">The challenge</a></h1>
<p>You are now well armed to face a challenge! Your task will be to implement the application I showed
you at the beginning of this chapter.</p>
<p>Here's the GIF again:</p>
<p align="center">
<img src="https://i.imgur.com/0k1r2Lc.gif">
</p>
<p>Also, this may help:</p>
<p align="center">
<img class="white_bg" src="05-led-roulette/../assets/timing-diagram.png">
</p>
<p>This is a timing diagram. It indicates which LED is on at any given instant of time and for how long
each LED should be on. On the X axis we have the time in milliseconds. The timing diagram shows a
single period. This pattern will repeat itself every 800 ms. The Y axis labels each LED with a
cardinal point: North, East, etc. As part of the challenge you'll have to figure out how each
element in the <code>Leds</code> array maps to these cardinal points (hint: <code>cargo doc --open</code> <code>;-)</code>).</p>
<p>Before you attempt this challenge, let me give you one additonal tip. Our GDB sessions always involve
entering the same commands at the beginning. We can use a <code>.gdb</code> file to execute some commands
right after GDB is started. This way you can save yourself the effort of having to enter them
manually on each GDB session.</p>
<p>As it turns out we've already created <code>../openocd.gdb</code> and you can see it's doing
pretty much what we did in the previous section plus a few other commands. Look at
the comments for additional information:</p>
<pre><code class="language-console">$ cat ../openocd.gdb
# Connect to gdb remote server
target remote :3333

# Load will flash the code
load

# Eanble demangling asm names on disassembly
set print asm-demangle on

# Enable pretty printing
set print pretty on

# Disable style sources as the default colors can be hard to read
set style sources off

# Initialize monitoring so iprintln! macro output
# is sent from the itm port to itm.txt
monitor tpiu config internal itm.txt uart off 8000000

# Turn on the itm port
monitor itm port 0 on

# Set a breakpoint at main, aka entry
break main

# Set a breakpiont at DefaultHandler
break DefaultHandler

# Set a breakpiont at HardFault
break HardFault

# Continue running and until we hit the main breakpoint
continue

# Step from the trampoline code in entry into main
step

</code></pre>
<p>Now we need to modify the <code>../.cargo/config.toml</code> file to execute <code>../openocd.gdb</code></p>
<pre><code class="language-console">nano ../.cargo/config.toml
</code></pre>
<p>Edit your <code>runner</code> command <code> -x ../openocd.gdb</code>.
Assuming you're using <code>arm-none-eabi-gdb</code> the diff is:</p>
<pre><code class="language-diff">~/embedded-discovery/src/05-led-roulette
$ git diff ../.cargo/config.toml
diff --git a/src/.cargo/config.toml b/src/.cargo/config.toml
index ddff17f..02ac952 100644
--- a/src/.cargo/config.toml
+++ b/src/.cargo/config.toml
@@ -1,5 +1,5 @@
 [target.thumbv7em-none-eabihf]
-runner = &quot;arm-none-eabi-gdb -q&quot;
+runner = &quot;arm-none-eabi-gdb -q -x ../openocd.gdb&quot;
 # runner = &quot;gdb-multiarch -q&quot;
 # runner = &quot;gdb -q&quot;
 rustflags = [
</code></pre>
<p>And the full contents of <code>../.cargo/config.toml</code>, again
assuming <code>arm-none-eabi-gdb</code>, is:</p>
<pre><code class="language-toml">[target.thumbv7em-none-eabihf]
runner = &quot;arm-none-eabi-gdb -q -x ../openocd.gdb&quot;
# runner = &quot;gdb-multiarch -q&quot;
# runner = &quot;gdb -q&quot;
rustflags = [
  &quot;-C&quot;, &quot;link-arg=-Tlink.x&quot;,
]

[build]
target = &quot;thumbv7em-none-eabihf&quot;

</code></pre>
<p>With that in place, you can now use a simple <code>cargo run</code> command which will build
the ARM version of the code and run the <code>gdb</code> session. The <code>gdb</code> session will
automatically flash the program and jump to the beginning of <code>main</code> as it <code>step</code>'s
through the entry trampoline:</p>
<pre><code class="language-console">cargo run
</code></pre>
<pre><code class="language-console">~/embedded-discovery/src/05-led-roulette (Update-05-led-roulette-WIP)
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `arm-none-eabi-gdb -q -x openocd.gdb ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...
led_roulette::__cortex_m_rt_main_trampoline () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x52c0 lma 0x8000194
Loading section .rodata, size 0xb50 lma 0x8005454
Start address 0x08000194, load size 24484
Transfer rate: 21 KB/sec, 6121 bytes/write.
Breakpoint 1 at 0x8000202: file ~/embedded-discovery/src/05-led-roulette/src/main.rs, line 7.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline ()
    at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]
led_roulette::__cortex_m_rt_main () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:9
9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
</code></pre>
<h2 id="fork-the-discovery-book"><a class="header" href="#fork-the-discovery-book">Fork the discovery book</a></h2>
<p>If you haven't already ready, it's probably a good idea to fork
the <a href="https://github.com/rust-embedded/discovery">embedded discovery book</a> so you
can save your changes in your own branch of your fork. We suggest creating
your own branch and leaving the <code>master</code> branch alone so the <code>master</code> branch
of your fork can stay in sync with the upstream repo. Also, it allows you to
more easily create PR's and improve this book, <strong>thank you in advance</strong>!</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="my-solution"><a class="header" href="#my-solution">My solution</a></h1>
<p>What solution did you come up with?</p>
<p>Here's mine:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux5::{Delay, DelayMs, LedArray, OutputSwitch, entry};

#[entry]
fn main() -&gt; ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let ms = 50_u8;
    loop {
        for curr in 0..8 {
            let next = (curr + 1) % 8;

            leds[next].on().ok();
            delay.delay_ms(ms);
            leds[curr].off().ok();
            delay.delay_ms(ms);
        }
    }
}
</code></pre></pre>
<p>One more thing! Check that your solution also works when compiled in &quot;release&quot; mode:</p>
<pre><code class="language-console">$ cargo build --target thumbv7em-none-eabihf --release
</code></pre>
<p>You can test it with this <code>gdb</code> command:</p>
<pre><code class="language-console">$ # or, you could simply call `cargo run --target thumbv7em-none-eabihf --release`
$ arm-none-eabi-gdb target/thumbv7em-none-eabihf/release/led-roulette
$ #                                              ~~~~~~~
</code></pre>
<p>Binary size is something we should always keep an eye on! How big is your solution? You can check
that using the <code>size</code> command on the release binary:</p>
<pre><code class="language-console">$ # equivalent to size target/thumbv7em-none-eabihf/debug/led-roulette
$ cargo size --target thumbv7em-none-eabihf --bin led-roulette -- -A
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
led-roulette  :
section               size        addr
.vector_table          404   0x8000000
.text                21144   0x8000194
.rodata               3144   0x800542c
.data                    0  0x20000000
.bss                     4  0x20000000
.uninit                  0  0x20000004
.debug_abbrev        19160         0x0
.debug_info         471239         0x0
.debug_aranges       18376         0x0
.debug_ranges       102536         0x0
.debug_str          508618         0x0
.debug_pubnames      76975         0x0
.debug_pubtypes     112797         0x0
.ARM.attributes         58         0x0
.debug_frame         55848         0x0
.debug_line         282067         0x0
.debug_loc             845         0x0
.comment               147         0x0
Total              1673362


$ cargo size --target thumbv7em-none-eabihf --bin led-roulette --release -- -A
    Finished release [optimized + debuginfo] target(s) in 0.03s
led-roulette  :
section              size        addr
.vector_table         404   0x8000000
.text                5380   0x8000194
.rodata               564   0x8001698
.data                   0  0x20000000
.bss                    4  0x20000000
.uninit                 0  0x20000004
.debug_loc           9994         0x0
.debug_abbrev        1821         0x0
.debug_info         74974         0x0
.debug_aranges        600         0x0
.debug_ranges        6848         0x0
.debug_str          52828         0x0
.debug_pubnames     20821         0x0
.debug_pubtypes     18891         0x0
.ARM.attributes        58         0x0
.debug_frame         1088         0x0
.debug_line         15307         0x0
.comment               19         0x0
Total              209601
</code></pre>
<blockquote>
<p><strong>NOTE</strong> The Cargo project is already configured to build the release binary using LTO.</p>
</blockquote>
<p>Know how to read this output? The <code>text</code> section contains the program instructions. It's around 5.25KB
in my case. On the other hand, the <code>data</code> and <code>bss</code> sections contain variables statically allocated
in RAM (<code>static</code> variables). A <code>static</code> variable is being used in <code>aux5::init</code>; that's why it shows 4
bytes of <code>bss</code>.</p>
<p>One final thing! We have been running our programs from within GDB but our programs doesn't depend on
GDB at all. You can confirm this be closing both GDB and OpenOCD and then resetting the board by
pressing the black button on the board. The LED roulette application will run without intervention
of GDB.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="hello-world"><a class="header" href="#hello-world">Hello, world!</a></h1>
<blockquote>
<p><strong>HEADS UP</strong> The &quot;solder bridge&quot; SB10 (see back of the board) on the STM32F3DISCOVERY, which is
required to use the ITM and the <code>iprint!</code> macros shown below, is <strong>not</strong> soldered by default
(see page 21 of the <a href="http://www.st.com/resource/en/user_manual/dm00063382.pdf">User Manual</a>).
(To be more accurate: this actually depends on the board revision. If you have an old version of
the board as the <a href="https://docs.rs-online.com/5192/0900766b814876f9.pdf">old User Manual</a> said, the SB10 was soldered. Check your board
to decide whether you need to fix it.)</p>
</blockquote>
<blockquote>
<p><strong>TL;DR</strong> You have two options to fix this: Either <strong>solder</strong> the solder bridge SB10 or connect a
female to female jumper wire between SWO and PB3 as shown in the picture below.</p>
</blockquote>
<p align="center">
<img height=640 title="Manual SWD connection" src="06-hello-world/../assets/f3-swd.png">
</p>
<hr />
<p>Just a little more of helpful magic before we start doing low level stuff.</p>
<p>Blinking an LED is like the &quot;Hello, world&quot; of the embedded world.</p>
<p>But in this section, we'll run a proper &quot;Hello, world&quot; program that prints stuff to your computer
console.</p>
<p>Go to the <code>06-hello-world</code> directory. There's some starter code in it:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux6::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    let mut itm = aux6::init();

    iprintln!(&amp;mut itm.stim[0], &quot;Hello, world!&quot;);

    loop {}
}
</code></pre></pre>
<p>The <code>iprintln</code> macro will format messages and output them to the microcontroller's <em>ITM</em>. ITM stands
for Instrumentation Trace Macrocell and it's a communication protocol on top of SWD (Serial Wire
Debug) which can be used to send messages from the microcontroller to the debugging host. This
communication is only <em>one way</em>: the debugging host can't send data to the microcontroller.</p>
<p>OpenOCD, which is managing the debug session, can receive data sent through this ITM <em>channel</em> and
redirect it to a file.</p>
<p>The ITM protocol works with <em>frames</em> (you can think of them as Ethernet frames). Each frame has a
header and a variable length payload. OpenOCD will receive these frames and write them directly to a
file without parsing them. So, if the microntroller sends the string &quot;Hello, world!&quot; using the
<code>iprintln</code> macro, OpenOCD's output file won't exactly contain that string.</p>
<p>To retrieve the original string, OpenOCD's output file will have to be parsed. We'll use the
<code>itmdump</code> program to perform the parsing as new data arrives.</p>
<p>You should have already installed the <code>itmdump</code> program during the <a href="06-hello-world/../03-setup/index.html#itmdump">installation chapter</a>.</p>
<p>In a new terminal, run this command inside the <code>/tmp</code> directory, if you are using a *nix OS, or from
within the <code>%TEMP%</code> directory, if you are running Windows. This should be the same directory from
where you are running OpenOCD.</p>
<blockquote>
<p><strong>NOTE</strong> It's very important that both <code>itmdump</code> and <code>openocd</code> are running
from the same directory!</p>
</blockquote>
<pre><code class="language-console">$ # itmdump terminal

$ # *nix
$ cd /tmp &amp;&amp; touch itm.txt

$ # Windows
$ cd %TEMP% &amp;&amp; type nul &gt;&gt; itm.txt

$ # both
$ itmdump -F -f itm.txt
</code></pre>
<p>This command will block as <code>itmdump</code> is now watching the <code>itm.txt</code> file. Leave this terminal open.</p>
<p>Make sure that the STM32F3DISCOVERY board is connected to your computer. Open another terminal
from <code>/tmp</code> directory (on Windows <code>%TEMP%</code>) to launch OpenOCD similar as described in <a href="06-hello-world/../03-setup/verify.html#first-openocd-connection">chapter 3</a>.</p>
<p>Alright. Now, let's build the starter code and flash it into the microcontroller.</p>
<p>We will now build and run the application, <code>cargo run</code>. And step through it using <code>next</code>.
Since <code>openocd.gdb</code> contains the <code>monitor</code> commands in <code>openocd.gdb</code> OpenOCD will redirect
the ITM output to itm.txt and <code>itmdump</code> will write it to its terminal window. Also, it setup
break points and stepped through the trampoline we are at the first executable
statement in <code>fn main()</code>:</p>
<pre><code class="language-console">~/embedded-discovery/src/06-hello-world
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `arm-none-eabi-gdb -q -x ../openocd.gdb ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/hello-world`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/hello-world...
hello_world::__cortex_m_rt_main () at ~/embedded-discovery/src/06-hello-world/src/main.rs:14
14          loop {}
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x2828 lma 0x8000194
Loading section .rodata, size 0x638 lma 0x80029bc
Start address 0x08000194, load size 12276
Transfer rate: 18 KB/sec, 4092 bytes/write.
Breakpoint 1 at 0x80001f0: file ~/embedded-discovery/src/06-hello-world/src/main.rs, line 8.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 2 at 0x800092a: file /home/wink/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs, line 570.
Breakpoint 3 at 0x80029a8: file /home/wink/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs, line 560.

Breakpoint 1, hello_world::__cortex_m_rt_main_trampoline () at ~/embedded-discovery/src/06-hello-world/src/main.rs:8
8       #[entry]
hello_world::__cortex_m_rt_main () at ~/embedded-discovery/src/06-hello-world/src/main.rs:10
10          let mut itm = aux6::init();

(gdb)
</code></pre>
<p>Now issue a <code>next</code> command which will execute <code>aux6::init()</code> and
stop at the next executable statement in <code>main.rs</code>, which
positions us at line 12:</p>
<pre><code class="language-text">(gdb) next
12	    iprintln!(&amp;mut itm.stim[0], &quot;Hello, world!&quot;);
</code></pre>
<p>Then issue another <code>next</code> command which will execute
line 12, executing the <code>iprintln</code> and stop at line 14:</p>
<pre><code class="language-text">(gdb) next
14	    loop {}
</code></pre>
<p>Now since <code>iprintln</code> has been executed the output on the <code>itmdump</code>
terminal window should be the <code>Hello, world!</code> string:</p>
<pre><code class="language-console">$ itmdump -F -f itm.txt
(...)
Hello, world!
</code></pre>
<p>Awesome, right? Feel free to use <code>iprintln</code> as a logging tool in the coming sections.</p>
<p>Next: That's not all! The <code>iprint!</code> macros are not the only thing that uses the ITM. <code>:-)</code></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="panic"><a class="header" href="#panic"><code>panic!</code></a></h1>
<p>The <code>panic!</code> macro also sends its output to the ITM!</p>
<p>Change the <code>main</code> function to look like this:</p>
<pre><pre class="playground"><code class="language-rust">#[entry]
fn main() -&gt; ! {
    panic!(&quot;Hello, world!&quot;);
}
</code></pre></pre>
<p>Before running one other suggestion, I find it inconvenient to have to
confirm when quitting gdb. Add the following file in your home
directory <code>~/.gdbinit</code> so that it quits immediately:</p>
<pre><code class="language-console">$ cat ~/.gdbinit
define hook-quit
  set confirm off
end
</code></pre>
<p>OK, now use <code>cargo run</code> and it stops at the first line of <code>fn main()</code>:</p>
<pre><code class="language-console">$ cargo run
   Compiling hello-world v0.2.0 (~/embedded-discovery/src/06-hello-world)
    Finished dev [unoptimized + debuginfo] target(s) in 0.11s
     Running `arm-none-eabi-gdb -q -x ../openocd.gdb ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/hello-world`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/hello-world...
hello_world::__cortex_m_rt_main () at ~/embedded-discovery/src/06-hello-world/src/main.rs:10
10          panic!(&quot;Hello, world!&quot;);
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x20fc lma 0x8000194
Loading section .rodata, size 0x554 lma 0x8002290
Start address 0x08000194, load size 10212
Transfer rate: 17 KB/sec, 3404 bytes/write.
Breakpoint 1 at 0x80001f0: file ~/embedded-discovery/src/06-hello-world/src/main.rs, line 8.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 2 at 0x8000222: file ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs, line 570.
Breakpoint 3 at 0x800227a: file ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs, line 560.

Breakpoint 1, hello_world::__cortex_m_rt_main_trampoline () at ~/embedded-discovery/src/06-hello-world/src/main.rs:8
8       #[entry]
hello_world::__cortex_m_rt_main () at ~/embedded-discovery/src/06-hello-world/src/main.rs:10
10          panic!(&quot;Hello, world!&quot;);
(gdb)
</code></pre>
<p>We'll use short command names to save typing, enter <code>c</code> then the <code>Enter</code> or <code>Return</code> key:</p>
<pre><code>(gdb) c
Continuing.
</code></pre>
<p>If all is well you'll see some new output in the <code>itmdump</code> terminal.</p>
<pre><code class="language-console">$ # itmdump terminal
(..)
panicked at 'Hello, world!', src/06-hello-world/src/main.rs:10:5
</code></pre>
<p>Then type <code>Ctrl-c</code> which breaks out of a loop in the runtime:</p>
<pre><code class="language-text">^C
Program received signal SIGINT, Interrupt.
0x0800115c in panic_itm::panic (info=0x20009fa0) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-itm-0.4.2/src/lib.rs:57
57	        atomic::compiler_fence(Ordering::SeqCst);
</code></pre>
<p>Ultimately, <code>panic!</code> is just another function call so you can see it leaves behind
a trace of function calls. This allows you to use <code>backtrace</code> or just <code>bt</code> and to see
call stack that caused the panic:</p>
<pre><code class="language-text">(gdb) bt
#0  panic_itm::panic (info=0x20009fa0) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-itm-0.4.2/src/lib.rs:47
#1  0x080005c2 in core::panicking::panic_fmt () at library/core/src/panicking.rs:92
#2  0x0800055a in core::panicking::panic () at library/core/src/panicking.rs:50
#3  0x08000210 in hello_world::__cortex_m_rt_main () at src/06-hello-world/src/main.rs:10
#4  0x080001f4 in hello_world::__cortex_m_rt_main_trampoline () at src/06-hello-world/src/main.rs:8
</code></pre>
<p>Another thing we can do is catch the panic <em>before</em> it does the logging.
So we'll do several things; reset to the beginning, disable breakpoint 1,
set a new breakpoint at <code>rust_begin_unwind</code>, list the break points and then continue:</p>
<pre><code class="language-text">(gdb) monitor reset halt
Unable to match requested speed 1000 kHz, using 950 kHz
Unable to match requested speed 1000 kHz, using 950 kHz
adapter speed: 950 kHz
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000194 msp: 0x2000a000

(gdb) disable 1

(gdb) break rust_begin_unwind 
Breakpoint 4 at 0x800106c: file ~/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-itm-0.4.2/src/lib.rs, line 47.

(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep n   0x080001f0 in hello_world::__cortex_m_rt_main_trampoline 
                                           at ~/prgs/rust/tutorial/embedded-discovery/src/06-hello-world/src/main.rs:8
        breakpoint already hit 1 time
2       breakpoint     keep y   0x08000222 in cortex_m_rt::DefaultHandler_ 
                                           at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:570
3       breakpoint     keep y   0x0800227a in cortex_m_rt::HardFault_ 
                                           at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:560
4       breakpoint     keep y   0x0800106c in panic_itm::panic 
                                           at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-itm-0.4.2/src/lib.rs:47

(gdb) c
Continuing.

Breakpoint 4, panic_itm::panic (info=0x20009fa0) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-itm-0.4.2/src/lib.rs:47
47          interrupt::disable();
</code></pre>
<p>You'll notice that nothing got printed on the <code>itmdump</code> console this time. If
you resume the program using <code>continue</code> then a new line will be printed.</p>
<p>In a later section we'll look into other simpler communication protocols.</p>
<p>Finally, enter the <code>q</code> command to quit and it quits immediately without asking for confirmation:</p>
<pre><code class="language-text">(gdb) q
Detaching from program: ~/prgs/rust/tutorial/embedded-discovery/target/thumbv7em-none-eabihf/debug/hello-world, Remote target
Ending remote debugging.
[Inferior 1 (Remote target) detached]
</code></pre>
<p>As an even shorter sequence you can type <code>Ctrl-d</code>, which eliminates
one keystroke!</p>
<blockquote>
<p><strong>NOTE</strong> In this case the <code>(gdb)</code> prompt is overwritten with <code>quit)</code></p>
</blockquote>
<pre><code class="language-text">quit)
Detaching from program: ~/prgs/rust/tutorial/embedded-discovery/target/thumbv7em-none-eabihf/debug/hello-world, Remote target
Ending remote debugging.
[Inferior 1 (Remote target) detached]
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="registers"><a class="header" href="#registers">Registers</a></h1>
<p>It's time to explore what the <code>Led</code> API does under the hood.</p>
<p>In a nutshell, it just writes to some special memory regions. Go into the <code>07-registers</code> directory
and let's run the starter code statement by statement.</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux7::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    aux7::init();

    unsafe {
        // A magic address!
        const GPIOE_BSRR: u32 = 0x48001018;

        // Turn on the &quot;North&quot; LED (red)
        *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 9;

        // Turn on the &quot;East&quot; LED (green)
        *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 11;

        // Turn off the &quot;North&quot; LED
        *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (9 + 16);

        // Turn off the &quot;East&quot; LED
        *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (11 + 16);
    }

    loop {}
}
</code></pre></pre>
<p>What's this magic?</p>
<p>The address <code>0x48001018</code> points to a <em>register</em>. A register is a special region of memory that
controls a <em>peripheral</em>. A peripheral is a piece of electronics that sits right next to the
processor within the microcontroller package and provides the processor with extra functionality.
After all, the processor, on its own, can only do math and logic.</p>
<p>This particular register controls General Purpose Input/Output (GPIO) <em>pins</em> (GPIO <em>is</em> a
peripheral) and can be used to <em>drive</em> each of those pins <em>low</em> or <em>high</em>.</p>
<h2 id="an-aside-leds-digital-outputs-and-voltage-levels"><a class="header" href="#an-aside-leds-digital-outputs-and-voltage-levels">An aside: LEDs, digital outputs and voltage levels</a></h2>
<p>Drive? Pin? Low? High?</p>
<p>A pin is a electrical contact. Our microcontroller has several of them and some of them are
connected to LEDs. An LED, a Light Emitting Diode, will only emit light when voltage is applied to
it with a certain polarity.</p>
<p align="center">
<img class="white_bg" height=180 title="LED circuit" src="https://upload.wikimedia.org/wikipedia/commons/c/c9/LED_circuit.svg">
</p>
<p>Luckily for us, the microcontroller's pins are connected to the LEDs with the right polarity. All
that we have to do is <em>output</em> some non-zero voltage through the pin to turn the LED on. The pins
attached to the LEDs are configured as <em>digital outputs</em> and can only output two different voltage
levels: &quot;low&quot;, 0 Volts, or &quot;high&quot;, 3 Volts. A &quot;high&quot; (voltage) level will turn the LED on whereas
a &quot;low&quot; (voltage) level will turn it off.</p>
<p>These &quot;low&quot; and &quot;high&quot; states map directly to the concept of digital logic. &quot;low&quot; is <code>0</code> or <code>false</code>
and &quot;high&quot; is <code>1</code> or <code>true</code>. This is why this pin configuration is known as digital output.</p>
<hr />
<p>OK. But how can one find out what this register does? Time to RTRM (Read the Reference Manual)!</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="rtrm-reading-the-reference-manual"><a class="header" href="#rtrm-reading-the-reference-manual">RTRM: Reading The Reference Manual</a></h1>
<p>I mentioned that the microcontroller has several pins. For convenience, these pins are grouped in
<em>ports</em> of 16 pins. Each port is named with a letter: Port A, Port B, etc. and the pins within each
port are named with numbers from 0 to 15.</p>
<p>The first thing we have to find out is which pin is connected to which LED. This information is in
the STM32F3DISCOVERY <a href="http://www.st.com/resource/en/user_manual/dm00063382.pdf">User Manual</a> (You downloaded a copy, right?). In this particular section:</p>
<blockquote>
<p>Section 6.4 LEDs - Page 18</p>
</blockquote>
<p>The manual says:</p>
<ul>
<li><code>LD3</code>, the North LED, is connected to the pin <code>PE9</code>. <code>PE9</code> is the short form of: Pin 9 on Port E.</li>
<li><code>LD7</code>, the East LED, is connected to the pin <code>PE11</code>.</li>
</ul>
<p>Up to this point, we know that we want to change the state of the pins PE9 and PE11 to turn the
North/East LEDs on/off. These pins are part of Port E so we'll have to deal with the <code>GPIOE</code>
peripheral.</p>
<p>Each peripheral has a register <em>block</em> associated to it. A register block is a collection of
registers allocated in contiguous memory. The address at which the register block starts is known as
its base address. We need to figure out what's the base address of the <code>GPIOE</code> peripheral. That
information is in the following section of the microcontroller <a href="http://www.st.com/resource/en/reference_manual/dm00043574.pdf">Reference Manual</a>:</p>
<blockquote>
<p>Section 3.2.2 Memory map and register boundary addresses - Page 51</p>
</blockquote>
<p>The table says that base address of the <code>GPIOE</code> register block is <code>0x4800_1000</code>.</p>
<p>Each peripheral also has its own section in the documentation. Each of these sections ends with a
table of the registers that the peripheral's register block contains. For the <code>GPIO</code> family of
peripheral, that table is in:</p>
<blockquote>
<p>Section 11.4.12 GPIO register map - Page 243</p>
</blockquote>
<p>'BSRR' is the register which we will be using to set/reset. Its offset value is '0x18' from the base address 
of the 'GPIOE'. We can look up BSRR in the reference manual. 
GPIO Registers -&gt; GPIO port bit set/reset register (GPIOx_BSRR).</p>
<p>Now we need to jump to the documentation of that particular register. It's a few pages above in:</p>
<blockquote>
<p>Section 11.4.7 GPIO port bit set/reset register (GPIOx_BSRR) - Page 240</p>
</blockquote>
<p>Finally!</p>
<p>This is the register we were writing to. The documentation says some interesting things. First, this
register is write only ... so let's try reading its value <code>:-)</code>.</p>
<p>We'll use GDB's <code>examine</code> command: <code>x</code>.</p>
<pre><code>(gdb) next
16              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 9;

(gdb) x 0x48001018
0x48001018:     0x00000000

(gdb) # the next command will turn the North LED on
(gdb) next
19              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 11;

(gdb) x 0x48001018
0x48001018:     0x00000000
</code></pre>
<p>Reading the register returns <code>0</code>. That matches what the documentation says.</p>
<p>The other thing that the documentation says is that the bits 0 to 15 can be used to <em>set</em> the
corresponding pin. That is bit 0 sets the pin 0. Here, <em>set</em> means outputting a <em>high</em> value on
the pin.</p>
<p>The documentation also says that bits 16 to 31 can be used to <em>reset</em> the corresponding pin. In this
case, the bit 16 resets the pin number 0. As you may guess, <em>reset</em> means outputting a <em>low</em> value
on the pin.</p>
<p>Correlating that information with our program, all seems to be in agreement:</p>
<ul>
<li>
<p>Writing <code>1 &lt;&lt; 9</code> (<code>BS9 = 1</code>)  to <code>BSRR</code>  sets <code>PE9</code> <em>high</em>. That turns the North LED <em>on</em>.</p>
</li>
<li>
<p>Writing <code>1 &lt;&lt; 11</code> (<code>BS11 = 1</code>) to <code>BSRR</code> sets <code>PE11</code> <em>high</em>. That turns the East LED <em>on</em>.</p>
</li>
<li>
<p>Writing <code>1 &lt;&lt; 25</code> (<code>BR9 = 1</code>) to <code>BSRR</code> sets <code>PE9</code> <em>low</em>. That turns the North LED <em>off</em>.</p>
</li>
<li>
<p>Finally, writing <code>1 &lt;&lt; 27</code> (<code>BR11 = 1</code>) to <code>BSRR</code> sets <code>PE11</code> <em>low</em>. That turns the East LED <em>off</em>.</p>
</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="misoptimization"><a class="header" href="#misoptimization">(mis)Optimization</a></h1>
<p>Reads/writes to registers are quite special. I may even dare to say that they are embodiment of side
effects. In the previous example we wrote four different values to the same register. If you didn't
know that address was a register, you may have simplified the logic to just write the final value <code>1 &lt;&lt; (11 + 16)</code> into the register.</p>
<p>Actually, LLVM, the compiler's backend / optimizer, does not know we are dealing with a register and
will merge the writes thus changing the behavior of our program. Let's check that really quick.</p>
<pre><code class="language-console">$ cargo run --release
(..)
Breakpoint 1, registers::__cortex_m_rt_main_trampoline () at src/07-registers/src/main.rs:7
7       #[entry]

(gdb) step
registers::__cortex_m_rt_main () at src/07-registers/src/main.rs:9
9           aux7::init();

(gdb) next
25              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (11 + 16);

(gdb) disassemble /m
Dump of assembler code for function _ZN9registers18__cortex_m_rt_main17h45b1ef53e18aa8d0E:
8       fn main() -&gt; ! {
   0x08000248 &lt;+0&gt;:     push    {r7, lr}
   0x0800024a &lt;+2&gt;:     mov     r7, sp

9           aux7::init();
   0x0800024c &lt;+4&gt;:     bl      0x8000260 &lt;aux7::init&gt;
   0x08000250 &lt;+8&gt;:     movw    r0, #4120       ; 0x1018
   0x08000254 &lt;+12&gt;:    mov.w   r1, #134217728  ; 0x8000000
   0x08000258 &lt;+16&gt;:    movt    r0, #18432      ; 0x4800

10
11          unsafe {
12              // A magic address!
13              const GPIOE_BSRR: u32 = 0x48001018;
14
15              // Turn on the &quot;North&quot; LED (red)
16              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 9;
17
18              // Turn on the &quot;East&quot; LED (green)
19              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 11;
20
21              // Turn off the &quot;North&quot; LED
22              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (9 + 16);
23
24              // Turn off the &quot;East&quot; LED
25              *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (11 + 16);
=&gt; 0x0800025c &lt;+20&gt;:    str     r1, [r0, #0]
   0x0800025e &lt;+22&gt;:    b.n     0x800025e &lt;registers::__cortex_m_rt_main+22&gt;

End of assembler dump.
</code></pre>
<p>The state of the LEDs didn't change this time! The <code>str</code> instruction is the one that writes a value
to the register. Our <em>debug</em> (unoptimized) program had four of them, one for each write to the
register, but the <em>release</em> (optimized) program only has one.</p>
<p>We can check that using <code>objdump</code> and capture the output to <code>out.asm</code>:</p>
<pre><code class="language-console"># same as cargo objdump -- -d --no-show-raw-insn --print-imm-hex --source target/thumbv7em-none-eabihf/debug/registers
cargo objdump --bin registers -- -d --no-show-raw-insn --print-imm-hex --source &gt; debug.txt
</code></pre>
<p>Then examine <code>debug.txt</code> looking for <code>main</code> and we see the 4 <code>str</code> instructions:</p>
<pre><code>080001ec &lt;main&gt;:
; #[entry]
 80001ec:       push    {r7, lr}
 80001ee:       mov     r7, sp
 80001f0:       bl      #0x2
 80001f4:       trap

080001f6 &lt;registers::__cortex_m_rt_main::hc2e3436fa38cd6f2&gt;:
; fn main() -&gt; ! {
 80001f6:       push    {r7, lr}
 80001f8:       mov     r7, sp
;     aux7::init();
 80001fa:       bl      #0x3e
 80001fe:       b       #-0x2 &lt;registers::__cortex_m_rt_main::hc2e3436fa38cd6f2+0xa&gt;
;         *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 9;
 8000200:       movw    r0, #0x2640
 8000204:       movt    r0, #0x800
 8000208:       ldr     r0, [r0]
 800020a:       movw    r1, #0x1018
 800020e:       movt    r1, #0x4800
 8000212:       str     r0, [r1]
;         *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; 11;
 8000214:       movw    r0, #0x2648
 8000218:       movt    r0, #0x800
 800021c:       ldr     r0, [r0]
 800021e:       str     r0, [r1]
;         *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (9 + 16);
 8000220:       movw    r0, #0x2650
 8000224:       movt    r0, #0x800
 8000228:       ldr     r0, [r0]
 800022a:       str     r0, [r1]
;         *(GPIOE_BSRR as *mut u32) = 1 &lt;&lt; (11 + 16);
 800022c:       movw    r0, #0x2638
 8000230:       movt    r0, #0x800
 8000234:       ldr     r0, [r0]
 8000236:       str     r0, [r1]
;     loop {}
 8000238:       b       #-0x2 &lt;registers::__cortex_m_rt_main::hc2e3436fa38cd6f2+0x44&gt;
 800023a:       b       #-0x4 &lt;registers::__cortex_m_rt_main::hc2e3436fa38cd6f2+0x44&gt;
 (..)
</code></pre>
<p>How do we prevent LLVM from misoptimizing our program? We use <em>volatile</em> operations instead of plain
reads/writes:</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

use core::ptr;

#[allow(unused_imports)]
use aux7::entry;

#[entry]
fn main() -&gt; ! {
    aux7::init();

    unsafe {
        // A magic address!
        const GPIOE_BSRR: u32 = 0x48001018;

        // Turn on the &quot;North&quot; LED (red)
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; 9);

        // Turn on the &quot;East&quot; LED (green)
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; 11);

        // Turn off the &quot;North&quot; LED
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; (9 + 16));

        // Turn off the &quot;East&quot; LED
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; (11 + 16));
    }

    loop {}
}

</code></pre></pre>
<p>Generate <code>release.txt</code> using with <code>--release</code> mode.</p>
<pre><code class="language-console">cargo objdump --release --bin registers -- -d --no-show-raw-insn --print-imm-hex --source &gt; release.txt
</code></pre>
<p>Now find the <code>main</code> routine in <code>release.txt</code> and we see the 4 <code>str</code> instructions.</p>
<pre><code>0800023e &lt;main&gt;:
; #[entry]
 800023e:       push    {r7, lr}
 8000240:       mov     r7, sp
 8000242:       bl      #0x2
 8000246:       trap

08000248 &lt;registers::__cortex_m_rt_main::h45b1ef53e18aa8d0&gt;:
; fn main() -&gt; ! {
 8000248:       push    {r7, lr}
 800024a:       mov     r7, sp
;     aux7::init();
 800024c:       bl      #0x22
 8000250:       movw    r0, #0x1018
 8000254:       mov.w   r1, #0x200
 8000258:       movt    r0, #0x4800
;         intrinsics::volatile_store(dst, src);
 800025c:       str     r1, [r0]
 800025e:       mov.w   r1, #0x800
 8000262:       str     r1, [r0]
 8000264:       mov.w   r1, #0x2000000
 8000268:       str     r1, [r0]
 800026a:       mov.w   r1, #0x8000000
 800026e:       str     r1, [r0]
 8000270:       b       #-0x4 &lt;registers::__cortex_m_rt_main::h45b1ef53e18aa8d0+0x28&gt;
 (..)
</code></pre>
<p>We see that the four writes (<code>str</code> instructions) are preserved. If you run it using
<code>gdb</code> you'll also see that we get the expected behavior.</p>
<blockquote>
<p>NB: The last <code>next</code> will endlessly execute <code>loop {}</code>, use <code>Ctrl-c</code> to get
back to the <code>(gdb)</code> prompt.</p>
</blockquote>
<pre><code>$ cargo run --release
(..)

Breakpoint 1, registers::__cortex_m_rt_main_trampoline () at src/07-registers/src/main.rs:9
9       #[entry]

(gdb) step
registers::__cortex_m_rt_main () at src/07-registers/src/main.rs:11
11          aux7::init();

(gdb) next
18              ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; 9);

(gdb) next
21              ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; 11);

(gdb) next
24              ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; (9 + 16));

(gdb) next
27              ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; (11 + 16));

(gdb) next
^C
Program received signal SIGINT, Interrupt.
0x08000270 in registers::__cortex_m_rt_main ()
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1124
1124            intrinsics::volatile_store(dst, src);
(gdb) 
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="0xbaaaaaad-address"><a class="header" href="#0xbaaaaaad-address"><code>0xBAAAAAAD</code> address</a></h1>
<p>Not all the peripheral memory can be accessed. Look at this program.</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

use core::ptr;

#[allow(unused_imports)]
use aux7::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    aux7::init();

    unsafe {
        ptr::read_volatile(0x4800_1800 as *const u32);
    }

    loop {}
}
</code></pre></pre>
<p>This address is close to the <code>GPIOE_BSRR</code> address we used before but this address is <em>invalid</em>.
Invalid in the sense that there's no register at this address.</p>
<p>Now, let's try it.</p>
<pre><code class="language-console">$ cargo run
(..)
Breakpoint 1, registers::__cortex_m_rt_main_trampoline () at src/07-registers/src/main.rs:9
9       #[entry]

(gdb) continue
Continuing.

Breakpoint 3, cortex_m_rt::HardFault_ (ef=0x20009fb0)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.13/src/lib.rs:560
560         loop {

(gdb)
</code></pre>
<p>We tried to do an invalid operation, reading memory that doesn't exist, so the processor raised an
<em>exception</em>, a <em>hardware</em> exception.</p>
<p>In most cases, exceptions are raised when the processor attempts to perform an invalid operation.
Exceptions break the normal flow of a program and force the processor to execute an <em>exception
handler</em>, which is just a function/subroutine.</p>
<p>There are different kind of exceptions. Each kind of exception is raised by different conditions and
each one is handled by a different exception handler.</p>
<p>The <code>aux7</code> crate depends on the <code>cortex-m-rt</code> crate which defines a default
<em>hard fault</em> handler, named <code>HardFault</code>, that handles the &quot;invalid memory
address&quot; exception. <code>openocd.gdb</code> placed a breakpoint on <code>HardFault</code>; that's why
the debugger halted your program while it was executing the exception handler.
We can get more information about the exception from the debugger. Let's see:</p>
<pre><code>(gdb) list
555     #[allow(unused_variables)]
556     #[doc(hidden)]
557     #[link_section = &quot;.HardFault.default&quot;]
558     #[no_mangle]
559     pub unsafe extern &quot;C&quot; fn HardFault_(ef: &amp;ExceptionFrame) -&gt; ! {
560         loop {
561             // add some side effect to prevent this from turning into a UDF instruction
562             // see rust-lang/rust#28728 for details
563             atomic::compiler_fence(Ordering::SeqCst);
564         }
</code></pre>
<p><code>ef</code> is a snapshot of the program state right before the exception occurred. Let's inspect it:</p>
<pre><code>(gdb) print/x *ef
$1 = cortex_m_rt::ExceptionFrame {
  r0: 0x48001800,
  r1: 0x80036b0,
  r2: 0x1,
  r3: 0x80000000,
  r12: 0xb,
  lr: 0x800020d,
  pc: 0x8001750,
  xpsr: 0xa1000200
}
</code></pre>
<p>There are several fields here but the most important one is <code>pc</code>, the Program Counter register.
The address in this register points to the instruction that generated the exception. Let's
disassemble the program around the bad instruction.</p>
<pre><code>(gdb) disassemble /m ef.pc
Dump of assembler code for function core::ptr::read_volatile&lt;u32&gt;:
1046    pub unsafe fn read_volatile&lt;T&gt;(src: *const T) -&gt; T {
   0x0800174c &lt;+0&gt;:     sub     sp, #12
   0x0800174e &lt;+2&gt;:     str     r0, [sp, #4]

1047        if cfg!(debug_assertions) &amp;&amp; !is_aligned_and_not_null(src) {
1048            // Not panicking to keep codegen impact smaller.
1049            abort();
1050        }
1051        // SAFETY: the caller must uphold the safety contract for `volatile_load`.
1052        unsafe { intrinsics::volatile_load(src) }
   0x08001750 &lt;+4&gt;:     ldr     r0, [r0, #0]
   0x08001752 &lt;+6&gt;:     str     r0, [sp, #8]
   0x08001754 &lt;+8&gt;:     ldr     r0, [sp, #8]
   0x08001756 &lt;+10&gt;:    str     r0, [sp, #0]
   0x08001758 &lt;+12&gt;:    b.n     0x800175a &lt;core::ptr::read_volatile&lt;u32&gt;+14&gt;

1053    }
   0x0800175a &lt;+14&gt;:    ldr     r0, [sp, #0]
   0x0800175c &lt;+16&gt;:    add     sp, #12
   0x0800175e &lt;+18&gt;:    bx      lr

End of assembler dump.
</code></pre>
<p>The exception was caused by the <code>ldr r0, [r0, #0]</code> instruction, a read instruction. The instruction
tried to read the memory at the address indicated by the <code>r0</code> register. By the way, <code>r0</code> is a CPU
(processor) register not a memory mapped register; it doesn't have an associated address like, say,
<code>GPIO_BSRR</code>.</p>
<p>Wouldn't it be nice if we could check what the value of the <code>r0</code> register was right at the instant
when the exception was raised? Well, we already did! The <code>r0</code> field in the <code>ef</code> value we printed
before is the value of <code>r0</code> register had when the exception was raised. Here it is again:</p>
<pre><code>(gdb) print/x *ef
$1 = cortex_m_rt::ExceptionFrame {
  r0: 0x48001800,
  r1: 0x80036b0,
  r2: 0x1,
  r3: 0x80000000,
  r12: 0xb,
  lr: 0x800020d,
  pc: 0x8001750,
  xpsr: 0xa1000200
}
</code></pre>
<p><code>r0</code> contains the value <code>0x4800_1800</code> which is the invalid address we called the <code>read_volatile</code>
function with.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="spooky-action-at-a-distance"><a class="header" href="#spooky-action-at-a-distance">Spooky action at a distance</a></h1>
<p><code>BSRR</code> is not the only register that can control the pins of Port E. The <code>ODR</code> register also lets
you change the value of the pins. Furthermore, <code>ODR</code> also lets you retrieve the current output
status of Port E.</p>
<p><code>ODR</code> is documented in:</p>
<blockquote>
<p>Section 11.4.6 GPIO port output data register - Page 239</p>
</blockquote>
<p>Let's look at this program. The key to this program
is <code>fn iprint_odr</code>. This function prints the current
value in <code>ODR</code> to the <code>ITM</code> console</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

use core::ptr;

#[allow(unused_imports)]
use aux7::{entry, iprintln, ITM};

// Print the current contents of odr
fn iprint_odr(itm: &amp;mut ITM) {
    const GPIOE_ODR: u32 = 0x4800_1014;

    unsafe {
        iprintln!(
            &amp;mut itm.stim[0],
            &quot;ODR = 0x{:04x}&quot;,
            ptr::read_volatile(GPIOE_ODR as *const u16)
        );
    }
}

#[entry]
fn main() -&gt; ! {
    let mut itm= aux7::init().0;

    unsafe {
        // A magic addresses!
        const GPIOE_BSRR: u32 = 0x4800_1018;

        // Print the initial contents of ODR
        iprint_odr(&amp;mut itm);

        // Turn on the &quot;North&quot; LED (red)
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; 9);
        iprint_odr(&amp;mut itm);

        // Turn on the &quot;East&quot; LED (green)
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; 11);
        iprint_odr(&amp;mut itm);

        // Turn off the &quot;North&quot; LED
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; (9 + 16));
        iprint_odr(&amp;mut itm);

        // Turn off the &quot;East&quot; LED
        ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 &lt;&lt; (11 + 16));
        iprint_odr(&amp;mut itm);
    }

    loop {}
}
</code></pre></pre>
<p>If you run this program</p>
<pre><code>$ cargo run
(..)
Breakpoint 1, registers::__cortex_m_rt_main_trampoline () at src/07-registers/src/main.rs:22
22      #[entry]

(gdb) continue
Continuing.
</code></pre>
<p>You'll see on itmdump's console:</p>
<pre><code class="language-console">$ # itmdump's console
(..)
ODR = 0x0000
ODR = 0x0200
ODR = 0x0a00
ODR = 0x0800
ODR = 0x0000
</code></pre>
<p>Side effects! Although we are reading the same address multiple times without actually modifying it,
we still see its value change every time <code>BSRR</code> is written to.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="type-safe-manipulation"><a class="header" href="#type-safe-manipulation">Type safe manipulation</a></h1>
<p>The last register we were working with, <code>ODR</code>, had this in its documentation:</p>
<blockquote>
<p>Bits 31:16 Reserved, must be kept at reset value</p>
</blockquote>
<p>We are not supposed to write to those bits of the register or Bad Stuff May Happen.</p>
<p>There's also the fact the registers have different read/write permissions. Some of them are write
only, others can be read and written to and there must be others that are read only.</p>
<p>Finally, directly working with hexadecimal addresses is error prone. You already saw that trying to
access an invalid memory address causes an exception which disrupts the execution of our program.</p>
<p>Wouldn't it be nice if we had an API to manipulate registers in a &quot;safe&quot; manner? Ideally, the API
should encode these three points I've mentioned: No messing around with the actual addresses, should
respect read/write permissions and should prevent modification of the reserved parts of a register.</p>
<p>Well, we do! <code>aux7::init()</code> actually returns a value that provides a type safe API to manipulate the
registers of the  <code>GPIOE</code> peripheral.</p>
<p>As you may remember: a group of registers associated to a peripheral is called register block, and
it's located in a contiguous region of memory. In this type safe API each register block is modeled
as a <code>struct</code> where each of its fields represents a register. Each register field is a different
newtype over e.g. <code>u32</code> that exposes a combination of the following methods: <code>read</code>, <code>write</code> or
<code>modify</code> according to its read/write permissions. Finally, these methods don't take primitive values
like <code>u32</code>, instead they take yet another newtype that can be constructed using the builder pattern
and that prevent the modification of the reserved parts of the register.</p>
<p>The best way to get familiar with this API is to port our running example to it.</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux7::{entry, iprintln, ITM, RegisterBlock};

#[entry]
fn main() -&gt; ! {
    let gpioe = aux7::init().1;

    // Turn on the North LED
    gpioe.bsrr.write(|w| w.bs9().set_bit());

    // Turn on the East LED
    gpioe.bsrr.write(|w| w.bs11().set_bit());

    // Turn off the North LED
    gpioe.bsrr.write(|w| w.br9().set_bit());

    // Turn off the East LED
    gpioe.bsrr.write(|w| w.br11().set_bit());

    loop {}
}
</code></pre></pre>
<p>First thing you notice: There are no magic addresses involved. Instead we use a more human friendly
way, for example <code>gpioe.bsrr</code>, to refer to the <code>BSRR</code> register in the <code>GPIOE</code> register block.</p>
<p>Then we have this <code>write</code> method that takes a closure. If the identity closure (<code>|w| w</code>) is used,
this method will set the register to its <em>default</em> (reset) value, the value it had right after the
microcontroller was powered on / reset. That value is <code>0x0</code> for the <code>BSRR</code> register. Since we want
to write a non-zero value to the register, we use builder methods like <code>bs9</code> and <code>br9</code> to set some
of the bits of the default value.</p>
<p>Let's run this program! There's some interesting stuff we can do <em>while</em> debugging the program.</p>
<p><code>gpioe</code> is a reference to the <code>GPIOE</code> register block. <code>print gpioe</code> will return the base address of
the register block.</p>
<pre><code>$ cargo run
(..)

Breakpoint 1, registers::__cortex_m_rt_main_trampoline () at src/07-registers/src/main.rs:7
7       #[entry]

(gdb) step
registers::__cortex_m_rt_main () at src/07-registers/src/main.rs:9
9           let gpioe = aux7::init().1;

(gdb) next
12          gpioe.bsrr.write(|w| w.bs9().set_bit());

(gdb) print gpioe
$1 = (*mut stm32f3::stm32f303::gpioc::RegisterBlock) 0x48001000
</code></pre>
<p>But if we instead <code>print *gpioe</code>, we'll get a <em>full view</em> of the register block: the value of each
of its registers will be printed.</p>
<pre><code>(gdb) print *gpioe
$2 = stm32f3::stm32f303::gpioc::RegisterBlock {
  moder: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_MODER&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 1431633920
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_MODER&gt;
  },
  otyper: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_OTYPER&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_OTYPER&gt;
  },
  ospeedr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_OSPEEDR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_OSPEEDR&gt;
  },
  pupdr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_PUPDR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_PUPDR&gt;
  },
  idr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_IDR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 204
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_IDR&gt;
  },
  odr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_ODR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_ODR&gt;
  },
  bsrr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_BSRR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_BSRR&gt;
  },
  lckr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_LCKR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_LCKR&gt;
  },
  afrl: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_AFRL&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_AFRL&gt;
  },
  afrh: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_AFRH&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_AFRH&gt;
  },
  brr: stm32f3::generic::Reg&lt;u32, stm32f3::stm32f303::gpioc::_BRR&gt; {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0
      }
    },
    _marker: core::marker::PhantomData&lt;stm32f3::stm32f303::gpioc::_BRR&gt;
  }
}
</code></pre>
<p>All these newtypes and closures sound like they'd generate large, bloated programs but, if you
actually compile the program in release mode with <a href="https://en.wikipedia.org/wiki/Interprocedural_optimization">LTO</a> enabled, you'll see that it produces exactly
the same instructions that the &quot;unsafe&quot; version that used <code>write_volatile</code> and hexadecimal addresses
did!</p>
<p>Use <code>cargo objdump</code> to grab the assembler code to <code>release.txt</code>:</p>
<pre><code class="language-console">cargo objdump --bin registers --release -- -d --no-show-raw-insn --print-imm-hex &gt; release.txt
</code></pre>
<p>Then search for <code>main</code> in <code>release.txt</code></p>
<pre><code>0800023e &lt;main&gt;:
 800023e:      	push	{r7, lr}
 8000240:      	mov	r7, sp
 8000242:      	bl	#0x2
 8000246:      	trap

08000248 &lt;registers::__cortex_m_rt_main::h199f1359501d5c71&gt;:
 8000248:      	push	{r7, lr}
 800024a:      	mov	r7, sp
 800024c:      	bl	#0x22
 8000250:      	movw	r0, #0x1018
 8000254:      	mov.w	r1, #0x200
 8000258:      	movt	r0, #0x4800
 800025c:      	str	r1, [r0]
 800025e:      	mov.w	r1, #0x800
 8000262:      	str	r1, [r0]
 8000264:      	mov.w	r1, #0x2000000
 8000268:      	str	r1, [r0]
 800026a:      	mov.w	r1, #0x8000000
 800026e:      	str	r1, [r0]
 8000270:      	b	#-0x4 &lt;registers::__cortex_m_rt_main::h199f1359501d5c71+0x28&gt;
</code></pre>
<p>The best part of all this is that nobody had to write a single line of code to implement the
GPIOE API. All the code was automatically generated from a System View Description (SVD) file using the
<a href="https://crates.io/crates/svd2rust">svd2rust</a> tool. This SVD file is actually an XML file that microcontroller vendors provide and that
contains the register maps of their microcontrollers. The file contains the layout of register
blocks, the base addresses, the read/write permissions of each register, the layout of the
registers, whether a register has reserved bits and lots of other useful information.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="leds-again"><a class="header" href="#leds-again">LEDs, again</a></h1>
<p>In the last section, I gave you <em>initialized</em> (configured) peripherals (I initialized them in
<code>aux7::init</code>). That's why just writing to <code>BSRR</code> was enough to control the LEDs. But, peripherals
are not <em>initialized</em> right after the microcontroller boots.</p>
<p>In this section, you'll have more fun with registers. I won't do any initialization and you'll have
to initialize and configure <code>GPIOE</code> pins as digital outputs pins so that you'll be able to drive LEDs
again.</p>
<p>This is the starter code.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux8::entry;

#[entry]
fn main() -&gt; ! {
    let (gpioe, rcc) = aux8::init();

    // TODO initialize GPIOE

    // Turn on all the LEDs in the compass
    gpioe.odr.write(|w| {
        w.odr8().set_bit();
        w.odr9().set_bit();
        w.odr10().set_bit();
        w.odr11().set_bit();
        w.odr12().set_bit();
        w.odr13().set_bit();
        w.odr14().set_bit();
        w.odr15().set_bit()
    });

    aux8::bkpt();

    loop {}
}
</code></pre></pre>
<p>If you run the starter code, you'll see that nothing happens this time. Furthermore, if you print
the <code>GPIOE</code> register block, you'll see that every register reads as zero even after the
<code>gpioe.odr.write</code> statement was executed!</p>
<pre><code>$ cargo run
Breakpoint 1, main () at src/08-leds-again/src/main.rs:9
9           let (gpioe, rcc) = aux8::init();

(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x08000f3c in __bkpt ()

(gdb) finish
Run till exit from #0  0x08000f3c in __bkpt ()
main () at src/08-leds-again/src/main.rs:25
25          aux8::bkpt();

(gdb) p/x *gpioe
$1 = stm32f30x::gpioc::RegisterBlock {
  moder: stm32f30x::gpioc::MODER {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  otyper: stm32f30x::gpioc::OTYPER {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  ospeedr: stm32f30x::gpioc::OSPEEDR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  pupdr: stm32f30x::gpioc::PUPDR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  idr: stm32f30x::gpioc::IDR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  odr: stm32f30x::gpioc::ODR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  bsrr: stm32f30x::gpioc::BSRR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  lckr: stm32f30x::gpioc::LCKR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  afrl: stm32f30x::gpioc::AFRL {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  afrh: stm32f30x::gpioc::AFRH {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  },
  brr: stm32f30x::gpioc::BRR {
    register: vcell::VolatileCell&lt;u32&gt; {
      value: core::cell::UnsafeCell&lt;u32&gt; {
        value: 0x0
      }
    }
  }
}
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="power"><a class="header" href="#power">Power</a></h1>
<p>Turns out that, to save power, most peripherals start in a powered off state -- that's their state
right after the microcontroller boots.</p>
<p>The Reset and Clock Control (<code>RCC</code>) peripheral can be used to power on or off every other
peripheral.</p>
<p>You can find the list of registers in the <code>RCC</code> register block in:</p>
<blockquote>
<p>Section 9.4.14 - RCC register map - Page 166 - Reference Manual</p>
</blockquote>
<p>The registers that control the power status of other peripherals are:</p>
<ul>
<li><code>AHBENR</code></li>
<li><code>APB1ENR</code></li>
<li><code>APB2ENR</code></li>
</ul>
<p>Each bit in these registers controls the power status of a single peripheral, including <code>GPIOE</code>.</p>
<p>Your task in this section is to power on the <code>GPIOE</code> peripheral. You'll have to:</p>
<ul>
<li>Figure out which of the three registers I mentioned before has the bit that controls the power
status.</li>
<li>Figure out what value that bit must be set to,<code>0</code> or <code>1</code>, to power on the <code>GPIOE</code> peripheral.</li>
<li>Finally, you'll have to change the starter code to <em>modify</em> the right register to turn on the
<code>GPIOE</code> peripheral.</li>
</ul>
<p>If you are successful, you'll see that the <code>gpioe.odr.write</code> statement will now be able to modify
the value of the <code>ODR</code> register.</p>
<p>Note that this won't be enough to actually turn on the LEDs.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="configuration"><a class="header" href="#configuration">Configuration</a></h1>
<p>After turning on the GPIOE peripheral, it still needs to be configured. In this case, we
want the pins to be configured as digital <em>outputs</em> so they can drive the LEDs; by default, most
pins are configured as digital <em>inputs</em>.</p>
<p>You can find the list of registers in the <code>GPIOE</code> register block in:</p>
<blockquote>
<p>Section 11.4.12 - GPIO registers - Page 243 - Reference Manual</p>
</blockquote>
<p>The register we'll have to deal with is: <code>MODER</code>.</p>
<p>Your task for this section is to further update the starter code to configure the <em>right</em> <code>GPIOE</code>
pins as digital outputs. You'll have to:</p>
<ul>
<li>Figure out <em>which</em> pins you need to configure as digital outputs. (hint: check Section 6.4 LEDs of
the <em>User Manual</em> (page 18)).</li>
<li>Read the documentation to understand what the bits in the <code>MODER</code> register do.</li>
<li>Modify the <code>MODER</code> register to configure the pins as digital outputs.</li>
</ul>
<p>If successful, you'll see the 8 LEDs turn on when you run the program.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="the-solution"><a class="header" href="#the-solution">The solution</a></h1>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux8::entry;

#[entry]
fn main() -&gt; ! {
    let (gpioe, rcc) = aux8::init();

    // enable the GPIOE peripheral
    rcc.ahbenr.write(|w| w.iopeen().set_bit());

    // configure the pins as outputs
    gpioe.moder.write(|w| {
        w.moder8().output();
        w.moder9().output();
        w.moder10().output();
        w.moder11().output();
        w.moder12().output();
        w.moder13().output();
        w.moder14().output();
        w.moder15().output()
    });

    // Turn on all the LEDs in the compass
    gpioe.odr.write(|w| {
        w.odr8().set_bit();
        w.odr9().set_bit();
        w.odr10().set_bit();
        w.odr11().set_bit();
        w.odr12().set_bit();
        w.odr13().set_bit();
        w.odr14().set_bit();
        w.odr15().set_bit()
    });

    aux8::bkpt();

    loop {}
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="clocks-and-timers"><a class="header" href="#clocks-and-timers">Clocks and timers</a></h1>
<p>In this section, we'll re-implement the LED roulette application. I'm going to give you back the
<code>Led</code> abstraction but this time I'm going to take away the <code>Delay</code> abstraction <code>:-)</code>.</p>
<p>Here's the starter code. The <code>delay</code> function is unimplemented so if you run this program the LEDs
will blink so fast that they'll appear to always be on.</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

use aux9::{entry, switch_hal::OutputSwitch, tim6};

#[inline(never)]
fn delay(tim6: &amp;tim6::RegisterBlock, ms: u16) {
    // TODO implement this
}

#[entry]
fn main() -&gt; ! {
    let (leds, rcc, tim6) = aux9::init();
    let mut leds = leds.into_array();

    // TODO initialize TIM6

    let ms = 50;
    loop {
        for curr in 0..8 {
            let next = (curr + 1) % 8;

            leds[next].on().unwrap();
            delay(tim6, ms);
            leds[curr].off().unwrap();
            delay(tim6, ms);
        }
    }
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="for-loop-delays"><a class="header" href="#for-loop-delays"><code>for</code> loop delays</a></h1>
<p>The first challenge is to implement the <code>delay</code> function without using any peripheral and the
obvious solution is to implement it as a <code>for</code> loop delay:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[inline(never)]
fn delay(tim6: &amp;tim6::RegisterBlock, ms: u16) {
    for _ in 0..1_000 {}
}
<span class="boring">}
</span></code></pre></pre>
<p>Of course, the above implementation is wrong because it always generates the same delay for any
value of <code>ms</code>.</p>
<p>In this section, you'll have to:</p>
<ul>
<li>Fix the <code>delay</code> function to generate delays proportional to its input <code>ms</code>.</li>
<li>Tweak the <code>delay</code> function to make the LED roulette spin at a rate of approximately 5 cycles in 4
seconds (800 milliseconds period).</li>
<li>The processor inside the microcontroller is clocked at 72 MHz and executes most instructions in one
&quot;tick&quot;, a cycle of its clock. How many (<code>for</code>) loops do  you <em>think</em> the <code>delay</code> function must do
to generate a delay of 1 second?</li>
<li>How many <code>for</code> loops does <code>delay(1000)</code> actually do?</li>
<li>What happens if compile your program in release mode and run it?</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="nop"><a class="header" href="#nop">NOP</a></h1>
<p>If in the previous section you compiled the program in release mode and actually looked at the
disassembly, you probably noticed that the <code>delay</code> function is optimized away and never gets called
from within <code>main</code>.</p>
<p>LLVM decided that the function wasn't doing anything worthwhile and just removed it.</p>
<p>There is a way to prevent LLVM from optimizing the <code>for</code> loop delay: add a <em>volatile</em> assembly
instruction. Any instruction will do but NOP (No OPeration) is a particular good choice in this case
because it has no side effect.</p>
<p>Your <code>for</code> loop delay would become:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[inline(never)]
fn delay(_tim6: &amp;tim6::RegisterBlock, ms: u16) {
    const K: u16 = 3; // this value needs to be tweaked
    for _ in 0..(K * ms) {
        aux9::nop()
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>And this time <code>delay</code> won't be compiled away by LLVM when you compile your program in release mode:</p>
<pre><code class="language-console">$ cargo objdump --bin clocks-and-timers --release -- -d --no-show-raw-insn
clocks-and-timers:      file format ELF32-arm-little

Disassembly of section .text:
clocks_and_timers::delay::h711ce9bd68a6328f:
 8000188:       push    {r4, r5, r7, lr}
 800018a:       movs    r4, #0
 800018c:       adds    r4, #1
 800018e:       uxth    r5, r4
 8000190:       bl      #4666
 8000194:       cmp     r5, #150
 8000196:       blo     #-14 &lt;clocks_and_timers::delay::h711ce9bd68a6328f+0x4&gt;
 8000198:       pop     {r4, r5, r7, pc}
</code></pre>
<p>Now, test this: Compile the program in debug mode and run it, then compile the program in release
mode and run it. What's the difference between them? What do you think is the main cause of the
difference? Can you think of a way to make them equivalent or at least more similar again?</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="one-shot-timer"><a class="header" href="#one-shot-timer">One-shot timer</a></h1>
<p>I hope that, by now, I have convinced you that <code>for</code> loop delays are a poor way to implement delays.</p>
<p>Now, we'll implement delays using a <em>hardware timer</em>. The basic function of a (hardware) timer is
... to keep precise track of time. A timer is yet another peripheral that's available to the
microcontroller; thus it can be controlled using registers.</p>
<p>The microcontroller we are using has several (in fact, more than 10) timers of different kinds
(basic, general purpose, and advanced timers) available to it. Some timers have more <em>resolution</em>
(number of bits) than others and some can be used for more than just keeping track of time.</p>
<p>We'll be using one of the <em>basic</em> timers: <code>TIM6</code>. This is one of the simplest timers available in
our microcontroller. The documentation for basic timers is in the following section:</p>
<blockquote>
<p>Section 22 Timers - Page 670 - Reference Manual</p>
</blockquote>
<p>Its registers are documented in:</p>
<blockquote>
<p>Section 22.4.9 TIM6/TIM7 register map - Page 682 - Reference Manual</p>
</blockquote>
<p>The registers we'll be using in this section are:</p>
<ul>
<li><code>SR</code>, the status register.</li>
<li><code>EGR</code>, the event generation register.</li>
<li><code>CNT</code>, the counter register.</li>
<li><code>PSC</code>, the prescaler register.</li>
<li><code>ARR</code>, the autoreload register.</li>
</ul>
<p>We'll be using the timer as a <em>one-shot</em> timer. It will sort of work like an alarm clock. We'll set
the timer to go off after some amount of time and then we'll wait until the timer goes off. The
documentation refers to this mode of operation as <em>one pulse mode</em>.</p>
<p>Here's a description of how a basic timer works when configured in one pulse mode:</p>
<ul>
<li>The counter is enabled by the user (<code>CR1.CEN = 1</code>).</li>
<li>The <code>CNT</code> register resets its value to zero and, on each tick, its value gets incremented by one.</li>
<li>Once the <code>CNT</code> register has reached the value of the <code>ARR</code> register, the counter will be disabled
by hardware (<code>CR1.CEN = 0</code>) and an <em>update event</em> will be raised (<code>SR.UIF = 1</code>).</li>
</ul>
<p><code>TIM6</code> is driven by the APB1 clock, whose frequency doesn't have to necessarily match the processor
frequency. That is, the APB1 clock could be running faster or slower. The default, however, is that
both APB1 and the processor are clocked at 8 MHz.</p>
<p>The tick mentioned in the functional description of the one pulse mode is <em>not</em> the same as one
tick of the APB1 clock. The <code>CNT</code> register increases at a frequency of <code>apb1 / (psc + 1)</code>
times per second, where <code>apb1</code> is the frequency of the APB1 clock and <code>psc</code> is the value of the
prescaler register, <code>PSC</code>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="initialization"><a class="header" href="#initialization">Initialization</a></h1>
<p>As with every other peripheral, we'll have to initialize this timer before we can use it. And just
as in the previous section, initialization is going to involve two steps: powering up the timer and
then configuring it.</p>
<p>Powering up the timer is easy: We just have to set <code>TIM6EN</code> bit to 1. This bit is in the <code>APB1ENR</code>
register of the <code>RCC</code> register block.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Power on the TIM6 timer
    rcc.apb1enr.modify(|_, w| w.tim6en().set_bit());
<span class="boring">}
</span></code></pre></pre>
<p>The configuration part is slightly more elaborate.</p>
<p>First, we'll have to configure the timer to operate in one pulse mode.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // OPM Select one pulse mode
    // CEN Keep the counter disabled for now
    tim6.cr1.write(|w| w.opm().set_bit().cen().clear_bit());
<span class="boring">}
</span></code></pre></pre>
<p>Then, we'll like to have the <code>CNT</code> counter operate at a frequency of 1 KHz because our <code>delay</code>
function takes a number of milliseconds as arguments and 1 KHz produces a 1 millisecond period. For
that we'll have to configure the prescaler.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Configure the prescaler to have the counter operate at 1 KHz
    tim6.psc.write(|w| w.psc().bits(psc));
<span class="boring">}
</span></code></pre></pre>
<p>I'm going to let you figure out the value of the prescaler, <code>psc</code>. Remember that the frequency of
the counter is <code>apb1 / (psc + 1)</code> and that <code>apb1</code> is 8 MHz.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="busy-waiting"><a class="header" href="#busy-waiting">Busy waiting</a></h1>
<p>The timer should now be properly initialized. All that's left is to implement the <code>delay</code> function
using the timer.</p>
<p>First thing we have to do is set the autoreload register (<code>ARR</code>) to make the timer go off in <code>ms</code>
milliseconds. Because the counter operates at 1 KHz, the autoreload value will be the same as <code>ms</code>.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Set the timer to go off in `ms` ticks
    // 1 tick = 1 ms
    tim6.arr.write(|w| w.arr().bits(ms));
<span class="boring">}
</span></code></pre></pre>
<p>Next, we need to enable the counter. It will immediately start counting.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // CEN: Enable the counter
    tim6.cr1.modify(|_, w| w.cen().set_bit());
<span class="boring">}
</span></code></pre></pre>
<p>Now we need to wait until the counter reaches the value of the autoreload register, <code>ms</code>, then we'll
know that <code>ms</code> milliseconds have passed. That condition is known as an <em>update event</em> and its
indicated by the <code>UIF</code> bit of the status register (<code>SR</code>).</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Wait until the alarm goes off (until the update event occurs)
    while !tim6.sr.read().uif().bit_is_set() {}
<span class="boring">}
</span></code></pre></pre>
<p>This pattern of just waiting until some condition is met, in this case that <code>UIF</code> becomes <code>1</code>, is
known as <em>busy waiting</em> and you'll see it a few more times in this text <code>:-)</code>.</p>
<p>Finally, we must clear (set to <code>0</code>) this <code>UIF</code> bit. If we don't, next time we enter the <code>delay</code>
function we'll think the update event has already happened and skip over the busy waiting part.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Clear the update event flag
    tim6.sr.modify(|_, w| w.uif().clear_bit());
<span class="boring">}
</span></code></pre></pre>
<p>Now, put this all together and check if it works as expected.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="putting-it-all-together"><a class="header" href="#putting-it-all-together">Putting it all together</a></h1>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

use aux9::{entry, switch_hal::OutputSwitch, tim6};

#[inline(never)]
fn delay(tim6: &amp;tim6::RegisterBlock, ms: u16) {
    // Set the timer to go off in `ms` ticks
    // 1 tick = 1 ms
    tim6.arr.write(|w| w.arr().bits(ms));

    // CEN: Enable the counter
    tim6.cr1.modify(|_, w| w.cen().set_bit());

    // Wait until the alarm goes off (until the update event occurs)
    while !tim6.sr.read().uif().bit_is_set() {}

    // Clear the update event flag
    tim6.sr.modify(|_, w| w.uif().clear_bit());
}

#[entry]
fn main() -&gt; ! {
    let (leds, rcc, tim6) = aux9::init();
    let mut leds = leds.into_array();

    // Power on the TIM6 timer
    rcc.apb1enr.modify(|_, w| w.tim6en().set_bit());

    // OPM Select one pulse mode
    // CEN Keep the counter disabled for now
    tim6.cr1.write(|w| w.opm().set_bit().cen().clear_bit());

    // Configure the prescaler to have the counter operate at 1 KHz
    // APB1_CLOCK = 8 MHz
    // PSC = 7999
    // 8 MHz / (7999 + 1) = 1 KHz
    // The counter (CNT) will increase on every millisecond
    tim6.psc.write(|w| w.psc().bits(7_999));

    let ms = 50;
    loop {
        for curr in 0..8 {
            let next = (curr + 1) % 8;

            leds[next].on().unwrap();
            delay(tim6, ms);
            leds[curr].off().unwrap();
            delay(tim6, ms);
        }
    }
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="serial-communication"><a class="header" href="#serial-communication">Serial communication</a></h1>
<a href="https://en.wikipedia.org/wiki/File:Serial_port.jpg">
<p align="center">
<img height="240" title="Standard serial port connector DE-9" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Serial_port.jpg/800px-Serial_port.jpg">
</p>
</a>
<p align="center">
<em>This is what we'll be using. I hope your computer has one!</em>
</p>
<p>Nah, don't worry. This connector, the DE-9, went out of fashion on PCs quite some time ago; it got
replaced by the Universal Serial Bus (USB). We won't be dealing with the DE-9 connector itself but
with the communication protocol that this cable is/was usually used for.</p>
<p>So what's this <a href="https://en.wikipedia.org/wiki/Asynchronous_serial_communication"><em>serial communication</em></a>? It's an <em>asynchronous</em> communication protocol where two
devices exchange data <em>serially</em>, as in one bit at a time, using two data lines (plus a common
ground). The protocol is asynchronous in the sense that neither of the shared lines carries a clock
signal. Instead both parties must agree on how fast data will be sent along the wire <em>before</em> the
communication occurs. This protocol allows <em>duplex</em> communication as data can be sent from A to B
and from B to A simultaneously.</p>
<p>We'll be using this protocol to exchange data between the microcontroller and your computer. In
contrast to the ITM protocol we have used before, with the serial communication protocol you can
send data from your computer to the microcontroller.</p>
<p>The next practical question you probably want to ask is: How fast can we send data through this
protocol?</p>
<p>This protocol works with frames. Each frame has one <em>start</em> bit, 5 to 9 bits of payload (data) and 1
to 2 <em>stop bits</em>. The speed of the protocol is known as <em>baud rate</em> and it's quoted in bits per
second (bps). Common baud rates are: 9600, 19200, 38400, 57600 and 115200 bps.</p>
<p>To actually answer the question: With a common configuration of 1 start bit, 8 bits of data, 1
stop bit and a baud rate of 115200 bps one can, in theory, send 11,520 frames per second. Since each
one frame carries a byte of data that results in a data rate of 11.52 KB/s. In practice, the data
rate will probably be lower because of processing times on the slower side of the communication (the
microcontroller).</p>
<p>Today's computers don't support the serial communication protocol. So you can't directly connect
your computer to the microcontroller. But that's where the serial module comes in. This module will
sit between the two and expose a serial interface to the microcontroller and an USB interface to
your computer. The microcontroller will see your computer as another serial device and your computer
will see the microcontroller as a virtual serial device.</p>
<p>Now, let's get familiar with the serial module and the serial communication tools that your OS
offers. Pick a route:</p>
<ul>
<li><a href="10-serial-communication/nix-tooling.html">*nix</a></li>
<li><a href="10-serial-communication/windows-tooling.html">Windows</a></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="nix-tooling"><a class="header" href="#nix-tooling">*nix tooling</a></h1>
<h2 id="newer-revisions-of-the-discovery-board"><a class="header" href="#newer-revisions-of-the-discovery-board">Newer revisions of the discovery board</a></h2>
<p>With newer revisions, if you connect the discovery board to your computer you
should see a new TTY device appear in <code>/dev</code>.</p>
<pre><code class="language-console">$ # Linux
$ dmesg | tail | grep -i tty
[13560.675310] cdc_acm 1-1.1:1.2: ttyACM0: USB ACM device
</code></pre>
<p>This is the USB &lt;-&gt; Serial device. On Linux, it's named <code>tty*</code> (usually
<code>ttyACM*</code> or <code>ttyUSB*</code>).</p>
<p>If you don't see the device appear then you probably have an older revision of
the board; check the next section, which contains instructions for older
revisions. If you do have a newer revision skip the next section and move to the
&quot;minicom&quot; section.</p>
<h2 id="older-revisions-of-the-discovery-board--external-serial-module"><a class="header" href="#older-revisions-of-the-discovery-board--external-serial-module">Older revisions of the discovery board / external serial module</a></h2>
<p>Connect the serial module to your computer and let's find out what name the OS assigned to it.</p>
<blockquote>
<p><strong>NOTE</strong> On macs, the USB device will named like this: <code>/dev/cu.usbserial-*</code>. You won't
find it using <code>dmesg</code>, instead use <code>ls -l /dev | grep cu.usb</code> and adjust the following 
commands accordingly!</p>
</blockquote>
<pre><code class="language-console">$ dmesg | grep -i tty
(..)
[  +0.000155] usb 3-2: FTDI USB Serial Device converter now attached to ttyUSB0
</code></pre>
<p>But what's this <code>ttyUSB0</code> thing? It's a file of course! Everything is a file in *nix:</p>
<pre><code class="language-console">$ ls -l /dev/ttyUSB0
crw-rw-rw- 1 root uucp 188, 0 Oct 27 00:00 /dev/ttyUSB0
</code></pre>
<blockquote>
<p><strong>NOTE</strong> if the permissions above is <code>crw-rw----</code>, the udev rules have not been set correctly
see <a href="10-serial-communication/../03-setup/linux.html#udev-rules">udev rules</a></p>
</blockquote>
<p>You can send out data by simply writing to this file:</p>
<pre><code class="language-console">$ echo 'Hello, world!' &gt; /dev/ttyUSB0
</code></pre>
<p>You should see the TX (red) LED on the serial module blink, just once and very fast!</p>
<h2 id="all-revisions-minicom"><a class="header" href="#all-revisions-minicom">All revisions: minicom</a></h2>
<p>Dealing with serial devices using <code>echo</code> is far from ergonomic. So, we'll use the program <code>minicom</code>
to interact with the serial device using the keyboard.</p>
<p>We must configure <code>minicom</code> before we use it. There are quite a few ways to do that but we'll use a
<code>.minirc.dfl</code> file in the home directory. Create a file in <code>~/.minirc.dfl</code> with the following
contents:</p>
<pre><code class="language-console">$ cat ~/.minirc.dfl
pu baudrate 115200
pu bits 8
pu parity N
pu stopbits 1
pu rtscts No
pu xonxoff No
</code></pre>
<blockquote>
<p><strong>NOTE</strong> Make sure this file ends in a newline! Otherwise, <code>minicom</code> will fail to read it.</p>
</blockquote>
<p>That file should be straightforward to read (except for the last two lines), but nonetheless let's
go over it line by line:</p>
<ul>
<li><code>pu baudrate 115200</code>. Sets baud rate to 115200 bps.</li>
<li><code>pu bits 8</code>. 8 bits per frame.</li>
<li><code>pu parity N</code>. No parity check.</li>
<li><code>pu stopbits 1</code>. 1 stop bit.</li>
<li><code>pu rtscts No</code>. No hardware control flow.</li>
<li><code>pu xonxoff No</code>. No software control flow.</li>
</ul>
<p>Once that's in place, we can launch <code>minicom</code>.</p>
<pre><code class="language-console">$ # NOTE you may need to use a different device here
$ minicom -D /dev/ttyACM0 -b 115200
</code></pre>
<p>This tells <code>minicom</code> to open the serial device at <code>/dev/ttyACM0</code> and set its
baud rate to 115200. A text-based user interface (TUI) will pop out.</p>
<p align="center">
<img title="minicom" src="10-serial-communication/../assets/minicom.png">
</p>
<p>You can now send data using the keyboard! Go ahead and type something. Note that
the TUI will <em>not</em> echo back what you type but, if you are using an external
module, you <em>may</em> see some LED on the module blink with each keystroke.</p>
<h2 id="minicom-commands"><a class="header" href="#minicom-commands"><code>minicom</code> commands</a></h2>
<p><code>minicom</code> exposes commands via keyboard shortcuts. On Linux, the shortcuts start with <code>Ctrl+A</code>. On
mac, the shortcuts start with the <code>Meta</code> key. Some useful commands below:</p>
<ul>
<li><code>Ctrl+A</code> + <code>Z</code>. Minicom Command Summary</li>
<li><code>Ctrl+A</code> + <code>C</code>. Clear the screen</li>
<li><code>Ctrl+A</code> + <code>X</code>. Exit and reset</li>
<li><code>Ctrl+A</code> + <code>Q</code>. Quit with no reset</li>
</ul>
<blockquote>
<p><strong>NOTE</strong> mac users: In the above commands, replace <code>Ctrl+A</code> with <code>Meta</code>.</p>
</blockquote>
<div style="break-before: page; page-break-before: always;"></div><h1 id="windows-tooling"><a class="header" href="#windows-tooling">Windows tooling</a></h1>
<p>Start by unplugging your discovery board.</p>
<p>Before plugging the discovery board or the serial module, run the following command on
the terminal:</p>
<pre><code class="language-console">$ mode
</code></pre>
<p>It will print a list of devices that are connected to your computer. The ones that start with <code>COM</code> in
their names are serial devices. This is the kind of device we'll be working with. Take note of all
the <code>COM</code> <em>ports</em> <code>mode</code> outputs <em>before</em> plugging the serial module.</p>
<p>Now, plug the discovery board and run the <code>mode</code> command again. If you see a new
<code>COM</code> port appear on the list then you have a newer revision of the discovery
and that's the COM port assigned to the serial functionality on the discovery.
You can skip the next paragraph.</p>
<p>If you didn't get a new COM port then you probably have an older revision of the
discovery. Now plug the serial module; you should see new COM port appear;
that's the COM port of the serial module.</p>
<p>Now launch <code>putty</code>. A GUI will pop out.</p>
<p align="center">
<img title="PuTTY settings" src="10-serial-communication/../assets/putty-session-choose-serial.png">
</p>
<p>On the starter screen, which should have the &quot;Session&quot; category open, pick &quot;Serial&quot; as the
&quot;Connection type&quot;. On the &quot;Serial line&quot; field enter the <code>COM</code> device you got on the previous step,
for example <code>COM3</code>.</p>
<p align="center">
<img title="PuTTY settings" src="10-serial-communication/../assets/putty-settings.png">
</p>
<p>Next, pick the &quot;Connection/Serial&quot; category from the menu on the left. On this new view, make sure
that the serial port is configured as follows:</p>
<ul>
<li>&quot;Speed (baud)&quot;: 115200</li>
<li>&quot;Data bits&quot;: 8</li>
<li>&quot;Stop bits&quot;: 1</li>
<li>&quot;Parity&quot;: None</li>
<li>&quot;Flow control&quot;: None</li>
</ul>
<p>Finally, click the Open button. A console will show up now:</p>
<p align="center">
<img title="PuTTY console" src="10-serial-communication/../assets/putty-console.png">
</p>
<p>If you type on this console, the TX (red) LED on the Serial module should blink. Each key stroke
should make the LED blink once. Note that the console won't echo back what you type so the screen
will remain blank.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="loopbacks"><a class="header" href="#loopbacks">Loopbacks</a></h1>
<p>We've tested sending data. It's time to test receiving it. Except that there's no other device that
can send us some data ... or is there?</p>
<p>Enter: loopbacks</p>
<p align="center">
<img title="Serial module loopback" src="10-serial-communication/../assets/serial-loopback.png">
</p>
<p>You can send data to yourself! Not very useful in production but very useful for debugging.</p>
<h2 id="older-board-revision--external-serial-module"><a class="header" href="#older-board-revision--external-serial-module">Older board revision / external serial module</a></h2>
<p>Connect the <code>TXO</code> and the <code>RXI</code> pins of the serial module together using a male to male jumper wire
as shown above.</p>
<p>Now enter some text into minicom/PuTTY and observe. What happens?</p>
<p>You should see three things:</p>
<ul>
<li>As before, the TX (red) LED blinks on each key press.</li>
<li>But now the RX (green) LED blinks on each key press as well! This indicates that the serial module
is receiving some data; the one it just sent.</li>
<li>Finally, on the minicom/PuTTY console, you should see that what you type echoes back to the
console.</li>
</ul>
<h2 id="newer-board-revision"><a class="header" href="#newer-board-revision">Newer board revision</a></h2>
<p>If you have a newer revision of the board you can set up a loopback by shorting
the PC4 and PC5 pins using a female to female jumper wire, like <a href="10-serial-communication/../06-hello-world/index.html">you did for the
SWO pin</a>.</p>
<p>You should now be able to send data to yourself.</p>
<p>Now try to enter some text into minicom/PuTTY and observe.</p>
<blockquote>
<p><strong>NOTE</strong>: To rule out the possibility of the existing firmware doing weird
things to the serial pins (PC4 and PC5) we recommend <em>holding</em> the reset
button while you enter text into minicom/PuTTY.</p>
</blockquote>
<p>If all is working you should see what you type echoed back to minicom/PuTTY
console.</p>
<hr />
<p>Now that you are familiar with sending and receiving data over serial port using minicom/PuTTY,
let's make your microcontroller and your computer talk!</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="usart"><a class="header" href="#usart">USART</a></h1>
<p>The microcontroller has a peripheral called USART, which stands for Universal
Synchronous/Asynchronous Receiver/Transmitter. This peripheral can be configured to work with
several communication protocols like the serial communication protocol.</p>
<p>Throughout this chapter, we'll use serial communication to exchange information between the
microcontroller and your computer. But before we do that we have to wire up everything.</p>
<p>I mentioned before that this protocol involves two data lines: TX and RX. TX stands for transmitter
and RX stands for receiver. Transmitter and receiver are relative terms though; which line is the
transmitter and which line is the receiver depends from which side of the communication you are
looking at the lines.</p>
<h3 id="newer-board-revisions"><a class="header" href="#newer-board-revisions">Newer board revisions</a></h3>
<p>If you have a newer revision of the board and are using the on-board USB &lt;-&gt;
Serial functionality then the <code>auxiliary</code> crate will set pin <code>PC4</code> as the TX
line and pin <code>PC5</code> as the RX line.</p>
<p>Everything is already wired on the board so you don't need to wire anything yourself.
You can move on to the <a href="11-usart/send-a-single-byte.html">next section</a>.</p>
<h3 id="older-board-revisions--external-serial-module"><a class="header" href="#older-board-revisions--external-serial-module">Older board revisions / external serial module</a></h3>
<p>If you are using an external USB &lt;-&gt; Serial module then you will <strong>need</strong> to
enable the <code>adapter</code> feature of the <code>aux11</code> crate dependency in <code>Cargo.toml</code>.</p>
<pre><code class="language-toml">[dependencies.aux11]
path = &quot;auxiliary&quot;
# enable this if you are going to use an external serial adapter
features = [&quot;adapter&quot;] # &lt;- uncomment this
</code></pre>
<p>We'll be using the pin <code>PA9</code> as the microcontroller's TX line and <code>PA10</code> as its RX line. In other
words, the pin <code>PA9</code> outputs data onto its wire whereas the pin <code>PA10</code> listens for data on its
wire.</p>
<p>We could have used a different pair of pins as the TX and RX pins. There's a table in page 44 of the
<a href="http://www.st.com/resource/en/datasheet/stm32f303vc.pdf">Data Sheet</a> that list all the other possible pins we could have used.</p>
<p>The serial module also has TX and RX pins. We'll have to <em>cross</em> these pins: that is connect the
microcontroller's TX pin to the serial module's RX pin and the micro's RX pin to the serial module's
TX pin. The wiring diagram below shows all the necessary connections.</p>
<p align="center">
<img height=640 title="F3 <-> Serial connection" src="../assets/f3-serial.png">
</p>
<p>These are the recommended steps to connect the microcontroller and the serial module:</p>
<ul>
<li>Close OpenOCD and <code>itmdump</code></li>
<li>Disconnect the USB cables from the F3 and the serial module.</li>
<li>Connect one of F3 GND pins to the GND pin of the serial module using a female to male (F/M) wire.
Preferably, a black one.</li>
<li>Connect the PA9 pin on the back of the F3 to the RXI pin of the serial module using a F/M wire.</li>
<li>Connect the PA10 pin on the back of the F3 to the TXO pin of the serial module using a F/M wire.</li>
<li>Now connect the USB cable to the F3.</li>
<li>Finally connect the USB cable to the Serial module.</li>
<li>Re-launch OpenOCD and <code>itmdump</code></li>
</ul>
<p>Everything's wired up! Let's proceed to send data back and forth.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="send-a-single-byte"><a class="header" href="#send-a-single-byte">Send a single byte</a></h1>
<p>Our first task will be to send a single byte from the microcontroller to the computer over the serial
connection.</p>
<p>This time, I'm going to provide you with an already initialized USART peripheral. You'll only have
to work with the registers that are in charge of sending and receiving data.</p>
<p>Go into the <code>11-usart</code> directory and let's run the starter code therein. Make sure that you have
minicom/PuTTY open.</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    let (usart1, _mono_timer, _itm) = aux11::init();

    // Send a single character
    usart1
        .tdr
        .write(|w| w.tdr().bits(u16::from(b'X')) );

    loop {}
}
</code></pre></pre>
<p>This program writes to the <code>TDR</code> register. This causes the <code>USART</code> peripheral to send one byte of
information through the serial interface.</p>
<p>On the receiving end, your computer, you should see show the character <code>X</code> appear on minicom/PuTTY's
terminal.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="send-a-string"><a class="header" href="#send-a-string">Send a string</a></h1>
<p>The next task will be to send a whole string from the microcontroller to your computer.</p>
<p>I want you to send the string <code>&quot;The quick brown fox jumps over the lazy dog.&quot;</code> from the microcontroller to
your computer.</p>
<p>It's your turn to write the program.</p>
<p>Execute your program inside the debugger, statement by statement. What do you see?</p>
<p>Then execute the program again but in <em>one go</em> using the <code>continue</code> command. What happens this time?</p>
<p>Finally, build the program in <em>release</em> mode and, again, run it in one go. What happens this time?</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="overruns"><a class="header" href="#overruns">Overruns</a></h1>
<p>If you wrote your program like this:</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    let (usart1, _mono_timer, _itm) = aux11::init();

    // Send a string
    for byte in b&quot;The quick brown fox jumps over the lazy dog.&quot;.iter() {
        usart1
            .tdr
            .write(|w| w.tdr().bits(u16::from(*byte)));
    }

    loop {}
}
</code></pre></pre>
<p>You probably received something like this on your computer when you executed the program compiled in
debug mode.</p>
<pre><code class="language-console">$ # minicom's terminal
(..)
The uic brwn oxjums oer helaz do.
</code></pre>
<p>And if you compiled in release mode, you probably only got something like this:</p>
<pre><code class="language-console">$ # minicom's terminal
(..)
T
</code></pre>
<p>What went wrong?</p>
<p>You see, sending bytes over the wire takes a relatively large amount of time. I already did the math
so let me quote myself:</p>
<blockquote>
<p>With a common configuration of 1 start bit, 8 bits of data, 1 stop bit and a baud rate of 115200
bps one can, in theory, send 11,520 frames per second. Since each one frame carries a byte of data
that results in a data rate of 11.52 KB/s</p>
</blockquote>
<p>Our pangram has a length of 45 bytes. That means it's going to take, at least, 3,900 microseconds
(<code>45 bytes / (11,520 bytes/s) = 3,906 us</code>) to send the string. The processor is working at 8 MHz,
where executing an instruction takes 125 nanoseconds, so it's likely going to be done with the <code>for</code>
loop in less than 3,900 microseconds.</p>
<p>We can actually time how long it takes to execute the <code>for</code> loop. <code>aux11::init()</code> returns a
<code>MonoTimer</code> (monotonic timer) value that exposes an <code>Instant</code> API that's similar to the one in
<code>std::time</code>.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    let (usart1, mono_timer, mut itm) = aux11::init();

    let instant = mono_timer.now();
    // Send a string
    for byte in b&quot;The quick brown fox jumps over the lazy dog.&quot;.iter() {
        usart1.tdr.write(|w| w.tdr().bits(u16::from(*byte)));
    }
    let elapsed = instant.elapsed(); // in ticks

    iprintln!(
        &amp;mut itm.stim[0],
        &quot;`for` loop took {} ticks ({} us)&quot;,
        elapsed,
        elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
    );

    loop {}
}
</code></pre></pre>
<p>In debug mode, I get:</p>
<pre><code class="language-console">$ # itmdump terminal
(..)
`for` loop took 22415 ticks (2801.875 us)
</code></pre>
<p>This is less than 3,900 microseconds but it's not that far off and that's why only a few bytes of
information are lost.</p>
<p>In conclusion, the processor is trying to send bytes at a faster rate than what the hardware can
actually handle and this results in data loss. This condition is known as buffer <em>overrun</em>.</p>
<p>How do we avoid this? The status register (<code>ISR</code>) has a flag, <code>TXE</code>, that indicates if it's &quot;safe&quot;
to write to the <code>TDR</code> register without incurring in data loss.</p>
<p>Let's use that to slowdown the processor.</p>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    let (usart1, mono_timer, mut itm) = aux11::init();

    let instant = mono_timer.now();
    // Send a string
    for byte in b&quot;The quick brown fox jumps over the lazy dog.&quot;.iter() {
        // wait until it's safe to write to TDR
        while usart1.isr.read().txe().bit_is_clear() {} // &lt;- NEW!

        usart1
            .tdr
            .write(|w| w.tdr().bits(u16::from(*byte)));
    }
    let elapsed = instant.elapsed(); // in ticks

    iprintln!(
        &amp;mut itm.stim[0],
        &quot;`for` loop took {} ticks ({} us)&quot;,
        elapsed,
        elapsed as f32 / mono_timer.frequency().0 as f32 * 1e6
    );

    loop {}
}
</code></pre></pre>
<p>This time, running the program in debug or release mode should result in a complete string on the
receiving side.</p>
<pre><code class="language-console">$ # minicom/PuTTY's console
(..)
The quick brown fox jumps over the lazy dog.
</code></pre>
<p>The timing of the <code>for</code> loop should be closer to the theoretical 3,900 microseconds as well. The
timing below is for the debug version.</p>
<pre><code class="language-console">$ # itmdump terminal
(..)
`for` loop took 30499 ticks (3812.375 us)
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="uprintln"><a class="header" href="#uprintln"><code>uprintln!</code></a></h1>
<p>For the next exercise, we'll implement the <code>uprint!</code> family of macros. Your goal is to make this
line of code work:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    uprintln!(serial, &quot;The answer is {}&quot;, 40 + 2);
<span class="boring">}
</span></code></pre></pre>
<p>Which must send the string <code>&quot;The answer is 42&quot;</code> through the serial interface.</p>
<p>How do we go about that? It's informative to look into the <code>std</code> implementation of <code>println!</code>.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// src/libstd/macros.rs
macro_rules! print {
    ($($arg:tt)*) =&gt; ($crate::io::_print(format_args!($($arg)*)));
}
<span class="boring">}
</span></code></pre></pre>
<p>Looks simple so far. We need the built-in <code>format_args!</code> macro (it's implemented in the compiler so we
can't see what it actually does). We'll have to use that macro in the exact same way. What does this
<code>_print</code> function do?</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// src/libstd/io/stdio.rs
pub fn _print(args: fmt::Arguments) {
    let result = match LOCAL_STDOUT.state() {
        LocalKeyState::Uninitialized |
        LocalKeyState::Destroyed =&gt; stdout().write_fmt(args),
        LocalKeyState::Valid =&gt; {
            LOCAL_STDOUT.with(|s| {
                if s.borrow_state() == BorrowState::Unused {
                    if let Some(w) = s.borrow_mut().as_mut() {
                        return w.write_fmt(args);
                    }
                }
                stdout().write_fmt(args)
            })
        }
    };
    if let Err(e) = result {
        panic!(&quot;failed printing to stdout: {}&quot;, e);
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>That <em>looks</em> complicated but the only part we are interested in is: <code>w.write_fmt(args)</code> and
<code>stdout().write_fmt(args)</code>. What <code>print!</code> ultimately does is call the <code>fmt::Write::write_fmt</code> method
with the output of <code>format_args!</code> as its argument.</p>
<p>Luckily we don't have to implement the <code>fmt::Write::write_fmt</code> method either because it's a default
method. We only have to implement the <code>fmt::Write::write_str</code> method.</p>
<p>Let's do that.</p>
<p>This is what the macro side of the equation looks like. What's left to be done by you is provide the
implementation of the <code>write_str</code> method.</p>
<p>Above we saw that <code>Write</code> is in <code>std::fmt</code>. We don't have access to <code>std</code> but <code>Write</code> is also
available in <code>core::fmt</code>.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use core::fmt::{self, Write};

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln, usart1};

macro_rules! uprint {
    ($serial:expr, $($arg:tt)*) =&gt; {
        $serial.write_fmt(format_args!($($arg)*)).ok()
    };
}

macro_rules! uprintln {
    ($serial:expr, $fmt:expr) =&gt; {
        uprint!($serial, concat!($fmt, &quot;\n&quot;))
    };
    ($serial:expr, $fmt:expr, $($arg:tt)*) =&gt; {
        uprint!($serial, concat!($fmt, &quot;\n&quot;), $($arg)*)
    };
}

struct SerialPort {
    usart1: &amp;'static mut usart1::RegisterBlock,
}

impl fmt::Write for SerialPort {
    fn write_str(&amp;mut self, s: &amp;str) -&gt; fmt::Result {
        // TODO implement this
        // hint: this will look very similar to the previous program
        Ok(())
    }
}

#[entry]
fn main() -&gt; ! {
    let (usart1, _mono_timer, _itm) = aux11::init();

    let mut serial = SerialPort { usart1 };

    uprintln!(serial, &quot;The answer is {}&quot;, 40 + 2);

    loop {}
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="receive-a-single-byte"><a class="header" href="#receive-a-single-byte">Receive a single byte</a></h1>
<p>So far we have sending data from the microcontroller to your computer. It's time to try the opposite: receiving
data from your computer.</p>
<p>There's a <code>RDR</code> register that will be filled with the data that comes from the RX line. If we read
that register, we'll retrieve the data that the other side of the channel sent. The question is: How
do we know that we have received (new) data? The status register, <code>ISR</code>, has a bit for that purpose:
<code>RXNE</code>. We can just busy wait on that flag.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};

#[entry]
fn main() -&gt; ! {
    let (usart1, _mono_timer, _itm) = aux11::init();

    loop {
        // Wait until there's data available
        while usart1.isr.read().rxne().bit_is_clear() {}

        // Retrieve the data
        let _byte = usart1.rdr.read().rdr().bits() as u8;

        aux11::bkpt();
    }
}
</code></pre></pre>
<p>Let's try this program! Let it run free using <code>continue</code> and then type a single character in
minicom/PuTTY's console. What happens? What are the contents of the <code>_byte</code> variable?</p>
<pre><code>(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x8003d48 in __bkpt ()

(gdb) finish
Run till exit from #0  0x8003d48 in __bkpt ()
usart::main () at src/11-usart/src/main.rs:19
19              aux11::bkpt();

(gdb) p/c _byte
$1 = 97 'a'
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="echo-server"><a class="header" href="#echo-server">Echo server</a></h1>
<p>Let's merge transmission and reception into a single program and write an echo server. An echo
server sends back to the client the same text it sent. For this application, the microcontroller
will be the server and you and your computer will be the client.</p>
<p>This should be straightforward to implement. (hint: do it byte by byte)</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="reverse-a-string"><a class="header" href="#reverse-a-string">Reverse a string</a></h1>
<p>Alright, next let's make the server more interesting by having it respond to the client with the
reverse of the text that they sent. The server will respond to the client every time they press the
ENTER key. Each server response will be in a new line.</p>
<p>This time you'll need a buffer; you can use <a href="https://docs.rs/heapless/latest/heapless/struct.Vec.html"><code>heapless::Vec</code></a>. Here's the starter code:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};
use heapless::Vec;

#[entry]
fn main() -&gt; ! {
    let (usart1, _mono_timer, _itm) = aux11::init();

    // A buffer with 32 bytes of capacity
    let mut buffer: Vec&lt;u8, 32&gt; = Vec::new();

    loop {
        buffer.clear();

        // TODO Receive a user request. Each user request ends with ENTER
        // NOTE `buffer.push` returns a `Result`. Handle the error by responding
        // with an error message.

        // TODO Send back the reversed string
    }
}

</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="my-solution-1"><a class="header" href="#my-solution-1">My solution</a></h1>
<pre><pre class="playground"><code class="language-rust">#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux11::{entry, iprint, iprintln};
use heapless::Vec;

#[entry]
fn main() -&gt; ! {
    let (usart1, _mono_timer, _itm) = aux11::init();

    // A buffer with 32 bytes of capacity
    let mut buffer: Vec&lt;u8, 32&gt; = Vec::new();

    loop {
        buffer.clear();

        loop {
            while usart1.isr.read().rxne().bit_is_clear() {}
            let byte = usart1.rdr.read().rdr().bits() as u8;

            if buffer.push(byte).is_err() {
                // buffer full
                for byte in b&quot;error: buffer full\n\r&quot; {
                    while usart1.isr.read().txe().bit_is_clear() {}
                    usart1
                        .tdr
                        .write(|w| w.tdr().bits(u16::from(*byte)));
                }

                break;
            }

            // Carriage return
            if byte == 13 {
                // Respond
                for byte in buffer.iter().rev().chain(&amp;[b'\n', b'\r']) {
                    while usart1.isr.read().txe().bit_is_clear() {}
                    usart1
                        .tdr
                        .write(|w| w.tdr().bits(u16::from(*byte)));
                }

                break;
            }
        }
    }
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="bluetooth-setup"><a class="header" href="#bluetooth-setup">Bluetooth setup</a></h1>
<p>It's time to get rid of some wires. Serial communication can not only be emulated on top of the USB
protocol; it can also be emulated on top of the Bluetooth protocol. This serial over Bluetooth
protocol is known as RFCOMM.</p>
<p>Before we use the Bluetooth module with the microcontroller, let's first interact with it using
minicom/PuTTY.</p>
<p>The first thing we'll need to do is: turn on the Bluetooth module. We'll have to share some of the
F3 power to it using the following connection:</p>
<p align="center">
<img height=640 title="F3 <-> Bluetooth connection (power only)" src="../assets/f3-bluetooth-power-only.png">
</p>
<p>The recommend steps to wire this up are:</p>
<ul>
<li>Close OpenOCD and <code>itmdump</code></li>
<li>Disconnect the USB cables from the F3 and the serial module.</li>
<li>Connect F3's GND pin to the Bluetooth's GND pin using a female to female (F/F) wire. Preferably, a
black one.</li>
<li>Connect F3's 5V pin to the Bluetooth's VCC pin using a F/F wire. Preferably, a red one.</li>
<li>Then, connect the USB cable back to the F3.</li>
<li>Re-launch OpenOCD and <code>itmdump</code></li>
</ul>
<p>Two LEDs, a blue one and a red one, on the Bluetooth module should start blinking right after you
power on the F3 board.</p>
<p>Next thing to do is pair your computer and the Bluetooth module. AFAIK, Windows and mac users can
simply use their OS default Bluetooth manager to do the pairing. The Bluetooth module default pin
is 1234.</p>
<p>Linux users will have to follow (some of) <a href="12-bluetooth-setup/linux.html">these instructions</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="linux-1"><a class="header" href="#linux-1">Linux</a></h1>
<p>If you have a graphical Bluetooth manager, you can use that to pair your computer to the Bluetooth
module and skip most of these steps. You'll probably still have to <a href="12-bluetooth-setup/linux.html#rfcomm-device">this step</a> though.</p>
<h2 id="power-up"><a class="header" href="#power-up">Power up</a></h2>
<p>First, your computer's Bluetooth transceiver may be OFF. Check its status with <code>hciconfig</code> and turn it
ON if necessary:</p>
<pre><code class="language-console">$ hciconfig
hci0:   Type: Primary  Bus: USB
        BD Address: 68:17:29:XX:XX:XX  ACL MTU: 310:10  SCO MTU: 64:8
        DOWN  &lt;--
        RX bytes:580 acl:0 sco:0 events:31 errors:0
        TX bytes:368 acl:0 sco:0 commands:30 errors:0

$ sudo hciconfig hci0 up

$ hciconfig
hci0:   Type: Primary  Bus: USB
        BD Address: 68:17:29:XX:XX:XX  ACL MTU: 310:10  SCO MTU: 64:8
        UP RUNNING  &lt;--
        RX bytes:1190 acl:0 sco:0 events:67 errors:0
        TX bytes:1072 acl:0 sco:0 commands:66 errors:0
</code></pre>
<p>Then you need to launch the BlueZ (Bluetooth) daemon:</p>
<ul>
<li>On systemd based Linux distributions, use:</li>
</ul>
<pre><code class="language-console">$ sudo systemctl start bluetooth
</code></pre>
<ul>
<li>On Ubuntu (or upstart based Linux distributions), use:</li>
</ul>
<pre><code class="language-console">$ sudo /etc/init.d/bluetooth start
</code></pre>
<p>You may also need to unblock your Bluetooth, depending on what <code>rfkill list</code> says:</p>
<pre><code class="language-console">$ rfkill list
9: hci0: Bluetooth
        Soft blocked: yes # &lt;--
        Hard blocked: no

$ sudo rfkill unblock bluetooth

$ rfkill list
9: hci0: Bluetooth
        Soft blocked: no  # &lt;--
        Hard blocked: no

</code></pre>
<h2 id="scan"><a class="header" href="#scan">Scan</a></h2>
<pre><code class="language-console">$ hcitool scan
Scanning ...
        20:16:05:XX:XX:XX       Ferris
$ #                             ^^^^^^
</code></pre>
<h2 id="pair"><a class="header" href="#pair">Pair</a></h2>
<pre><code class="language-console">$ bluetoothctl
[bluetooth]# scan on
[bluetooth]# agent on
[bluetooth]# pair 20:16:05:XX:XX:XX
Attempting to pair with 20:16:05:XX:XX:XX
[CHG] Device 20:16:05:XX:XX:XX Connected: yes
Request PIN code
[agent] Enter PIN code: 1234
</code></pre>
<h2 id="rfcomm-device"><a class="header" href="#rfcomm-device">rfcomm device</a></h2>
<p>We'll create a device file for our Bluetooth module in <code>/dev</code>. Then we'll be able to use it just
like we used <code>/dev/ttyUSB0</code>.</p>
<pre><code class="language-console">$ sudo rfcomm bind 0 20:16:05:XX:XX:XX
</code></pre>
<p>Because we used <code>0</code> as an argument to <code>bind</code>, <code>/dev/rfcomm0</code> will be the device file assigned to our
Bluetooth module.</p>
<p>You can release (destroy) the device file at any time with the following command:</p>
<pre><code class="language-console">$ # Don't actually run this command right now!
$ sudo rfcomm release 0
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="loopback-again"><a class="header" href="#loopback-again">Loopback, again</a></h1>
<p>After pairing your computer to the Bluetooth module, your OS should have created a device file / COM
port for you. On Linux, it should be <code>/dev/rfcomm*</code>; on mac, it should be <code>/dev/cu.*</code>; and on
Windows, it should be a new COM port.</p>
<p>We can now test the Bluetooth module with minicom/PuTTY. Because this module doesn't have LED
indicators for the transmission and reception events like the serial module did, we'll test the
module using a loopback connection:</p>
<p align="center">
<img height=640 title="F3 <-> Bluetooth connection (loopback)" src="../assets/f3-bluetooth-loopback.png">
</p>
<p>Just connect the module's TXD pin to its RXD pin using a F/F wire.</p>
<p>Now, connect to the device using <code>minicom</code>/<code>PuTTY</code>:</p>
<pre><code class="language-console">$ minicom -D /dev/rfcomm0
</code></pre>
<p>Upon connecting, the blinking pattern of the Bluetooth module should change to: long pause then
blink twice quickly.</p>
<p>Typing inside minicom/PuTTY terminal should echo back what you type.</p>
<div style="break-before: page; page-break-before: always;"></div><h2 id="at-commands"><a class="header" href="#at-commands">AT commands</a></h2>
<p>The Bluetooth module and the F3 need to be configured to communicate at the same baud rate. The tutorial code initializes the UART1 serial device to a baud rate of 115200. The HC-05 Bluetooth module is configured at a baud rate of 9600 by default.</p>
<p>The Bluetooth module supports an AT mode that allows you to examine and change its configuration and settings. To utilize the AT mode, connect the Bluetooth module to the F3 and FTDI as shown in the following diagram.</p>
<p align="center">
<img height=640 title="Bluetooth <-> Serial connection" src="../assets/bluetooth-serial.png">
</p>
<p>Recommended steps to enter AT mode:</p>
<ul>
<li>Disconnect the F3 and FTDI from your computer.</li>
<li>Connect F3's GND pin to the Bluetooth's GND pin using a Female/Female (F/F) wire
(preferably, a black one).</li>
<li>Connect F3's 5V pin to the Bluetooth's VCC pin using a F/F wire (preferably, a
red one).</li>
<li>Connect the FTDI RXI pin to the Bluetooth's TXD pin using a Female/Male (F/M) wire.</li>
<li>Connect the FTDI TXO pin to the Bluetooth's RXD pin using a Female/Male (F/M) wire.</li>
<li>Now connect the FTDI to your computer via USB cable.</li>
<li>Next connect the F3 to your computer via USB cable while simultaneously pressing and holding the button on the Bluetooth module (kinda tricky).</li>
<li>Now, release the button and the Bluetooth module will enter AT mode. You can confirm this by observing that the red LED on the Bluetooth module is blinking in a slow pattern (approx 1-2 seconds on/off).</li>
</ul>
<p>The AT mode always operates at a baud rate of 38400, so configure your terminal program for that baud rate and connect to the FTDI device.</p>
<p>When your serial connection is established, you may get a bunch of <code>ERROR: (0)</code> repeatedly being displayed. If this happens, just hit ENTER to stop the errors.</p>
<h3 id="sanity-check"><a class="header" href="#sanity-check">Sanity check</a></h3>
<pre><code>$ at
OK
OK
(etc...)
</code></pre>
<p>Answers <code>OK</code> repeatedly until you hit ENTER again.</p>
<h3 id="rename-the-device"><a class="header" href="#rename-the-device">Rename the device</a></h3>
<pre><code>$ at+name=ferris
OK
</code></pre>
<h3 id="query-for-the-current-baud-rate-of-the-bluetooth-module"><a class="header" href="#query-for-the-current-baud-rate-of-the-bluetooth-module">Query for the current baud rate of the Bluetooth module</a></h3>
<pre><code>at+uart?
+UART:9600,0,0
OK
+UART:9600,0,0
OK
(etc ...)
</code></pre>
<h3 id="change-the-baud-rate"><a class="header" href="#change-the-baud-rate">Change the baud rate</a></h3>
<pre><code>$ at+uart=115200,0,0
OK
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="serial-over-bluetooth"><a class="header" href="#serial-over-bluetooth">Serial over Bluetooth</a></h1>
<p>Now that we verify that the Bluetooth module works with minicom/PuTTY, let's connect it to the
microcontroller:</p>
<p align="center">
<img height=640 title="F3 <-> Bluetooth connection" src="../assets/f3-bluetooth.png">
</p>
<p>Recommended steps to wire this up:</p>
<ul>
<li>Close OpenOCD and <code>itmdump</code>.</li>
<li>Disconnect the F3 from your computer.</li>
<li>Connect F3's GND pin to the module's GND pin using a female to female (F/F) wire (preferably, a
black one).</li>
<li>Connect F3's 5V pin to the module's VCC pin using a F/F wire (preferably, a red one).</li>
<li>Connect the PA9 (TX) pin on the back of the F3 to the Bluetooth's RXD pin using a F/F wire.</li>
<li>Connect the PA10 (RX) pin on the back of the F3 to the Bluetooth's TXD pin using a F/F wire.</li>
<li>Now connect the F3 and your computer using an USB cable.</li>
<li>Re-launch OpenOCD and <code>itmdump</code>.</li>
</ul>
<p>And that's it! You should be able to run all the programs you wrote in <a href="13-serial-over-bluetooth/../11-usart/index.html">section 11</a> without
modification! Just make sure you open the right serial device / COM port.</p>
<p><strong>NOTE</strong> If you are having trouble communicating with the bluetooth device, you may need to initialize USART1 with a lower baud rate. Lowering it from 115,200 bps to 9,600 bps might help, as described <a href="https://github.com/rust-embedded/discovery/blob/master/src/11-usart/auxiliary/src/lib.rs#L31">here</a></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="i2c"><a class="header" href="#i2c">I2C</a></h1>
<p>We just saw the serial communication protocol. It's a widely used protocol because it's very
simple and this simplicity makes it easy to implement on top of other protocols like Bluetooth and
USB.</p>
<p>However, it's simplicity is also a downside. More elaborated data exchanges, like reading a digital
sensor, would require the sensor vendor to come up with another protocol on top of it.</p>
<p>(Un)Luckily for us, there are <em>plenty</em> of other communication protocols in the embedded space. Some
of them are widely used in digital sensors.</p>
<p>The F3 board we are using has three motion sensors in it: an accelerometer, a magnetometer and
gyroscope. The accelerometer and magnetometer are packaged in a single component and can be accessed
via an I2C bus.</p>
<p>I2C stands for Inter-Integrated Circuit and is a <em>synchronous</em> <em>serial</em> communication protocol. It
uses two lines to exchange data: a data line (SDA) and a clock line (SCL). Because a clock line is
used to synchronize the communication, this is a <em>synchronous</em> protocol.</p>
<p align="center">
<img class="white_bg" height=180 title="I2C bus" src="https://upload.wikimedia.org/wikipedia/commons/3/3e/I2C.svg">
</p>
<p>This protocol uses a <em>master</em> <em>slave</em> model where the master is the device that <em>starts</em> and
drives the communication with a slave device. Several devices, both masters and slaves, can be
connected to the same bus at the same time. A master device can communicate with a specific slave
device by first broadcasting its <em>address</em> to the bus. This address can be 7 bits or 10 bits long.
Once a master has <em>started</em> a communication with a slave, no other device can make use of the bus
until the master <em>stops</em> the communication.</p>
<p>The clock line determines how fast data can be exchanged and it usually operates at a frequency of
100 KHz (standard mode) or 400 KHz (fast mode).</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="general-protocol"><a class="header" href="#general-protocol">General protocol</a></h1>
<p>The I2C protocol is more elaborate than the serial communication protocol because it has to support
communication between several devices. Let's see how it works using examples:</p>
<h2 id="master---slave"><a class="header" href="#master---slave">Master -&gt; Slave</a></h2>
<p>If the master wants to send data to the slave:</p>
<p align="center">
  <img class="white_bg" height=180 title="I2C bus" src="https://upload.wikimedia.org/wikipedia/commons/3/3e/I2C.svg">
</p>
<ol>
<li>Master: Broadcast START</li>
<li>M: Broadcast slave address (7 bits) + the R/W (8th) bit set to WRITE</li>
<li>Slave: Responds ACK (ACKnowledgement)</li>
<li>M: Send one byte</li>
<li>S: Responds ACK</li>
<li>Repeat steps 4 and 5 zero or more times</li>
<li>M: Broadcast STOP OR (broadcast RESTART and go back to (2))</li>
</ol>
<blockquote>
<p><strong>NOTE</strong> The slave address could have been 10 bits instead of 7 bits long. Nothing else would have
changed.</p>
</blockquote>
<h2 id="master---slave-1"><a class="header" href="#master---slave-1">Master &lt;- Slave</a></h2>
<p>If the master wants to read data from the slave:</p>
<p align="center">
<img class="white_bg" height=180 title="I2C bus" src="https://upload.wikimedia.org/wikipedia/commons/3/3e/I2C.svg">
</p>
<ol>
<li>M: Broadcast START</li>
<li>M: Broadcast slave address (7 bits) + the R/W (8th) bit set to READ</li>
<li>S: Responds with ACK</li>
<li>S: Send byte</li>
<li>M: Responds with ACK</li>
<li>Repeat steps 4 and 5 zero or more times</li>
<li>M: Broadcast STOP OR (broadcast RESTART and go back to (2))</li>
</ol>
<blockquote>
<p><strong>NOTE</strong> The slave address could have been 10 bits instead of 7 bits long. Nothing else would have
changed.</p>
</blockquote>
<div style="break-before: page; page-break-before: always;"></div><h1 id="lsm303dlhc"><a class="header" href="#lsm303dlhc">LSM303DLHC</a></h1>
<p>* <strong>NOTE</strong>: Newer (from around 2020/09) Discovery boards may have an <a href="https://www.st.com/resource/en/datasheet/lsm303agr.pdf">LSM303AGR</a>
rather than a <a href="http://www.st.com/resource/en/datasheet/lsm303dlhc.pdf">LSM303DLHC</a>. 
Checkout the github issues like <a href="https://github.com/rust-embedded/discovery/issues/274">this</a> for more details. </p>
<p>Two of the sensors in the F3, the magnetometer and the accelerometer, are packaged in a single
component: the LSM303DLHC integrated circuit. These two sensors can be accessed via an I2C bus. Each
sensor behaves like an I2C slave and has a <em>different</em> address.</p>
<p>Each sensor has its own memory where it stores the results of sensing its environment. Our
interaction with these sensors will mainly involve reading their memory.</p>
<p>The memory of these sensors is modeled as byte addressable registers. These sensors can be
configured too; that's done by writing to their registers. So, in a sense, these sensors are very
similar to the peripherals <em>inside</em> the microcontroller. The difference is that their registers are
not mapped into the microcontrollers' memory. Instead, their registers have to be accessed via the
I2C bus.</p>
<p>The main source of information about the LSM303DLHC is its <a href="http://www.st.com/resource/en/datasheet/lsm303dlhc.pdf">Data Sheet</a>. Read through it to see how
one can read the sensors' registers. That part is in:</p>
<blockquote>
<p>Section 5.1.1 I2C Operation - Page 20 - LSM303DLHC Data Sheet</p>
</blockquote>
<p>The other part of the documentation relevant to this book is the description of the registers. That
part is in:</p>
<blockquote>
<p>Section 7 Register description - Page 25 - LSM303DLHC Data Sheet</p>
</blockquote>
<div style="break-before: page; page-break-before: always;"></div><h1 id="read-a-single-register"><a class="header" href="#read-a-single-register">Read a single register</a></h1>
<p>Let's put all that theory into practice!</p>
<p>Just like with the USART peripheral, I've taken care of initializing everything before you reach
<code>main</code> so you'll only have to deal with the following registers:</p>
<ul>
<li><code>CR2</code>. Control register 2.</li>
<li><code>ISR</code>. Interrupt and status register.</li>
<li><code>TXDR</code>. Transmit data register.</li>
<li><code>RXDR</code>. Receive data register.</li>
</ul>
<p>These registers are documented in the following section of the Reference Manual:</p>
<blockquote>
<p>Section 28.7 I2C registers - Page 868 - Reference Manual</p>
</blockquote>
<p>We'll be using the <code>I2C1</code> peripheral in conjunction with pins <code>PB6</code> (<code>SCL</code>) and <code>PB7</code> (<code>SDA</code>).</p>
<p>You won't have to wire anything this time because the sensor is on the board and it's already
connected to the microcontroller. However, I would recommend that you disconnect the serial /
Bluetooth module from the F3 to make it easier to manipulate. Later on, we'll be moving the board
around quite a bit.</p>
<p>Your task is to write a program that reads the contents of the magnetometer's <code>IRA_REG_M</code> register.
This register is read only and always contains the value <code>0b01001000</code>.</p>
<p>The microcontroller will be taking the role of the I2C master and the magnetometer inside the
LSM303DLHC will be the I2C slave.</p>
<p>Here's the starter code. You'll have to implement the <code>TODO</code>s.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux14::{entry, iprint, iprintln, prelude::*};

// Slave address
const MAGNETOMETER: u16 = 0b0011_1100;

// Addresses of the magnetometer's registers
const OUT_X_H_M: u8 = 0x03;
const IRA_REG_M: u8 = 0x0A;

#[entry]
fn main() -&gt; ! {
    let (i2c1, _delay, mut itm) = aux14::init();

    // Stage 1: Send the address of the register we want to read to the
    // magnetometer
    {
        // TODO Broadcast START

        // TODO Broadcast the MAGNETOMETER address with the R/W bit set to Write

        // TODO Send the address of the register that we want to read: IRA_REG_M
    }

    // Stage 2: Receive the contents of the register we asked for
    let byte = {
        // TODO Broadcast RESTART

        // TODO Broadcast the MAGNETOMETER address with the R/W bit set to Read

        // TODO Receive the contents of the register

        // TODO Broadcast STOP
        0
    };

    // Expected output: 0x0A - 0b01001000
    iprintln!(&amp;mut itm.stim[0], &quot;0x{:02X} - 0b{:08b}&quot;, IRA_REG_M, byte);

    loop {}
}
</code></pre></pre>
<p>To give you some extra help, these are the exact bitfields you'll be working with:</p>
<ul>
<li><code>CR2</code>: <code>SADD1</code>, <code>RD_WRN</code>, <code>NBYTES</code>, <code>START</code>, <code>AUTOEND</code></li>
<li><code>ISR</code>: <code>TXIS</code>, <code>RXNE</code>, <code>TC</code></li>
<li><code>TXDR</code>: <code>TXDATA</code></li>
<li><code>RXDR</code>: <code>RXDATA</code></li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="the-solution-1"><a class="header" href="#the-solution-1">The solution</a></h1>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux14::{entry, iprint, iprintln, prelude::*};

// Slave address
const MAGNETOMETER: u16 = 0b0011_1100;

// Addresses of the magnetometer's registers
const OUT_X_H_M: u8 = 0x03;
const IRA_REG_M: u8 = 0x0A;

#[entry]
fn main() -&gt; ! {
    let (i2c1, _delay, mut itm) = aux14::init();

    // Stage 1: Send the address of the register we want to read to the
    // magnetometer
    {
        // Broadcast START
        // Broadcast the MAGNETOMETER address with the R/W bit set to Write
        i2c1.cr2.write(|w| {
            w.start().set_bit();
            w.sadd().bits(MAGNETOMETER);
            w.rd_wrn().clear_bit();
            w.nbytes().bits(1);
            w.autoend().clear_bit()
        });

        // Wait until we can send more data
        while i2c1.isr.read().txis().bit_is_clear() {}

        // Send the address of the register that we want to read: IRA_REG_M
        i2c1.txdr.write(|w| w.txdata().bits(IRA_REG_M));

        // Wait until the previous byte has been transmitted
        while i2c1.isr.read().tc().bit_is_clear() {}
    }

    // Stage 2: Receive the contents of the register we asked for
    let byte = {
        // Broadcast RESTART
        // Broadcast the MAGNETOMETER address with the R/W bit set to Read
        i2c1.cr2.modify(|_, w| {
            w.start().set_bit();
            w.nbytes().bits(1);
            w.rd_wrn().set_bit();
            w.autoend().set_bit()
        });

        // Wait until we have received the contents of the register
        while i2c1.isr.read().rxne().bit_is_clear() {}

        // Broadcast STOP (automatic because of `AUTOEND = 1`)

        i2c1.rxdr.read().rxdata().bits()
    };

    // Expected output: 0x0A - 0b01001000
    iprintln!(&amp;mut itm.stim[0], &quot;0x{:02X} - 0b{:08b}&quot;, IRA_REG_M, byte);

    loop {}
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="read-several-registers"><a class="header" href="#read-several-registers">Read several registers</a></h1>
<p>Reading the <code>IRA_REG_M</code> register was a good test of our understanding of the I2C protocol but that
register contains uninteresting information.</p>
<p>This time, we'll read the registers of the magnetometer that actually expose the sensor readings.
Six contiguous registers are involved and they start with <code>OUT_X_H_M</code> at address <code>0x03</code>.</p>
<p>We'll modify our previous program to read these six registers. Only a few modifications are needed.</p>
<p>We'll need to change the address we request from the magnetometer from <code>IRA_REG_M</code> to <code>OUT_X_H_M</code>.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Send the address of the register that we want to read: OUT_X_H_M
    i2c1.txdr.write(|w| w.txdata().bits(OUT_X_H_M));
<span class="boring">}
</span></code></pre></pre>
<p>We'll have to request the slave for six bytes rather than just one.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    // Broadcast RESTART
    // Broadcast the MAGNETOMETER address with the R/W bit set to Read
    i2c1.cr2.modify(|_, w| {
        w.start().set_bit();
        w.nbytes().bits(6);
        w.rd_wrn().set_bit();
        w.autoend().set_bit()
    });
<span class="boring">}
</span></code></pre></pre>
<p>And fill a buffer rather than read just one byte:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>    let mut buffer = [0u8; 6];
    for byte in &amp;mut buffer {
        // Wait until we have received the contents of the register
        while i2c1.isr.read().rxne().bit_is_clear() {}

        *byte = i2c1.rxdr.read().rxdata().bits();
    }

    // Broadcast STOP (automatic because of `AUTOEND = 1`)
<span class="boring">}
</span></code></pre></pre>
<p>Putting it all together inside a loop alongside a delay to reduce the data throughput:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux14::{entry, iprint, iprintln, prelude::*};

// Slave address
const MAGNETOMETER: u16 = 0b0011_1100;

// Addresses of the magnetometer's registers
const OUT_X_H_M: u8 = 0x03;
const IRA_REG_M: u8 = 0x0A;

#[entry]
fn main() -&gt; ! {
    let (i2c1, mut delay, mut itm) = aux14::init();

    loop {
        // Broadcast START
        // Broadcast the MAGNETOMETER address with the R/W bit set to Write
        i2c1.cr2.write(|w| {
            w.start().set_bit();
            w.sadd().bits(MAGNETOMETER);
            w.rd_wrn().clear_bit();
            w.nbytes().bits(1);
            w.autoend().clear_bit()
        });

        // Wait until we can send more data
        while i2c1.isr.read().txis().bit_is_clear() {}

        // Send the address of the register that we want to read: OUT_X_H_M
        i2c1.txdr.write(|w| w.txdata().bits(OUT_X_H_M));

        // Wait until the previous byte has been transmitted
        while i2c1.isr.read().tc().bit_is_clear() {}

        // Broadcast RESTART
        // Broadcast the MAGNETOMETER address with the R/W bit set to Read
        i2c1.cr2.modify(|_, w| {
            w.start().set_bit();
            w.nbytes().bits(6);
            w.rd_wrn().set_bit();
            w.autoend().set_bit()
        });

        let mut buffer = [0u8; 6];
        for byte in &amp;mut buffer {
            // Wait until we have received something
            while i2c1.isr.read().rxne().bit_is_clear() {}

            *byte = i2c1.rxdr.read().rxdata().bits();
        }
        // Broadcast STOP (automatic because of `AUTOEND = 1`)

        iprintln!(&amp;mut itm.stim[0], &quot;{:?}&quot;, buffer);

        delay.delay_ms(1_000_u16);
    }
}
</code></pre></pre>
<p>If you run this, you should printed in the <code>itmdump</code>'s console a new array of six bytes every
second. The values within the array should change if you move around the board.</p>
<pre><code class="language-console">$ # itmdump terminal
(..)
[0, 45, 255, 251, 0, 193]
[0, 44, 255, 249, 0, 193]
[0, 49, 255, 250, 0, 195]
</code></pre>
<p>But these bytes don't make much sense like that. Let's turn them into actual readings:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>        let x_h = u16::from(buffer[0]);
        let x_l = u16::from(buffer[1]);
        let z_h = u16::from(buffer[2]);
        let z_l = u16::from(buffer[3]);
        let y_h = u16::from(buffer[4]);
        let y_l = u16::from(buffer[5]);

        let x = ((x_h &lt;&lt; 8) + x_l) as i16;
        let y = ((y_h &lt;&lt; 8) + y_l) as i16;
        let z = ((z_h &lt;&lt; 8) + z_l) as i16;

        iprintln!(&amp;mut itm.stim[0], &quot;{:?}&quot;, (x, y, z));
<span class="boring">}
</span></code></pre></pre>
<p>Now it should look better:</p>
<pre><code class="language-console">$ # `itmdump terminal
(..)
(44, 196, -7)
(45, 195, -6)
(46, 196, -9)
</code></pre>
<p>This is the Earth's magnetic field decomposed alongside the XYZ axis of the magnetometer.</p>
<p>In the next section, we'll learn how to make sense of these numbers.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="led-compass"><a class="header" href="#led-compass">LED compass</a></h1>
<p>In this section, we'll implement a compass using the LEDs on the F3. Like proper compasses, our LED
compass must point north somehow. It will do that by turning on one of its eight LEDs; the on LED
should point towards north.</p>
<p>Magnetic fields have both a magnitude, measured in Gauss or Teslas, and a <em>direction</em>. The
magnetometer on the F3 measures both the magnitude and the direction of an external magnetic field
but it reports back the <em>decomposition</em> of said field along <em>its axes</em>.</p>
<p>See below, the magnetometer has three axes associated to it.</p>
<p align="center">
<img height=480 title="Magnetometer axes" src="15-led-compass/../assets/f3-lsm303dlhc.png">
</p>
<p>Only the X and Y axes are shown above. The Z axis is pointing &quot;out&quot; of your screen.</p>
<p>Let's get familiar with the readings of the magnetometer by running the following starter code:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*};

#[entry]
fn main() -&gt; ! {
    let (_leds, mut lsm303dlhc, mut delay, mut itm) = aux15::init();

    loop {
        iprintln!(&amp;mut itm.stim[0], &quot;{:?}&quot;, lsm303dlhc.mag().unwrap());
        delay.delay_ms(1_000_u16);
    }
}
</code></pre></pre>
<p>This <code>lsm303dlhc</code> module provides high level API over the LSM303DLHC. Under the hood it does the
same I2C routine that you implemented in the last section but it reports the X, Y and Z values in a
<code>I16x3</code> struct instead of a tuple.</p>
<p>Locate where north is at your current location. Then rotate the board such that it's aligned
&quot;towards north&quot;: the North LED (LD3) should be pointing towards north.</p>
<p>Now run the starter code and observe the output. What X, Y and Z values do you see?</p>
<pre><code class="language-console">$ # itmdump terminal
(..)
I16x3 { x: 45, y: 194, z: -3 }
I16x3 { x: 46, y: 195, z: -8 }
I16x3 { x: 47, y: 197, z: -2 }
</code></pre>
<p>Now rotate the board 90 degrees while keeping it parallel to the ground. What X, Y and Z values do
you see this time? Then rotate it 90 degrees again. What values do you see?</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="take-1"><a class="header" href="#take-1">Take 1</a></h1>
<p>What's the simplest way in which we can implement the LED compass? Even if it's not perfect.</p>
<p>For starters, we'd only care about the X and Y components of the magnetic field because when you
look at a compass you always hold it in horizontal position thus the compass is in the XY plane.</p>
<p>For example, what LED would you turn on in the following case. EMF stands for Earth's Magnetic Field
and green arrow has the direction of the EMF (it points north).</p>
<p align="center">
<img title="Quadrant I" src="15-led-compass/../assets/quadrant-i.png">
</p
<p>The <code>Southeast</code> LED, right?</p>
<p>What <em>signs</em> do the X and Y components of the magnetic field have in that scenario? Both are
positive.</p>
<p>If we only looked at the signs of the X and Y components we could determine to which quadrant the
magnetic field belongs to.</p>
<p align="center">
<img class="white_bg" title="Quadrants" src="15-led-compass/../assets/quadrants.png">
</p>
<p>In the previous example, the magnetic field was in the first quadrant (x and y were positive) and it
made sense to turn on the <code>SouthEast</code> LED. Similarly, we could turn a different LED if the magnetic
field was in a different quadrant.</p>
<p>Let's try that logic. Here's the starter code:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*, switch_hal::OutputSwitch, Direction, I16x3};

#[entry]
fn main() -&gt; ! {
    let (leds, mut lsm303dlhc, mut delay, _itm) = aux15::init();
    let mut leds = leds.into_array();

    loop {
        let I16x3 { x, y, .. } = lsm303dlhc.mag().unwrap();

        // Look at the signs of the X and Y components to determine in which
        // quadrant the magnetic field is
        let dir = match (x &gt; 0, y &gt; 0) {
            // Quadrant ???
            (true, true) =&gt; Direction::Southeast,
            // Quadrant ???
            (false, true) =&gt; panic!(&quot;TODO&quot;),
            // Quadrant ???
            (false, false) =&gt; panic!(&quot;TODO&quot;),
            // Quadrant ???
            (true, false) =&gt; panic!(&quot;TODO&quot;),
        };

        leds.iter_mut().for_each(|led| led.off().unwrap());
        leds[dir as usize].on().unwrap();

        delay.delay_ms(1_000_u16);
    }
}
</code></pre></pre>
<p>There's a <code>Direction</code> enum in the <code>led</code> module that has 8 variants named after the cardinal points:
<code>North</code>, <code>East</code>, <code>Southwest</code>, etc. Each of these variants represent one of the 8 LEDs in the
compass. The <code>Leds</code> value can be indexed using the <code>Direction</code> <code>enum</code>; the result of indexing is the
LED that points in that <code>Direction</code>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="solution-1"><a class="header" href="#solution-1">Solution 1</a></h1>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*, switch_hal::OutputSwitch, Direction, I16x3};

#[entry]
fn main() -&gt; ! {
    let (leds, mut lsm303dlhc, mut delay, _itm) = aux15::init();
    let mut leds = leds.into_array();

    loop {
        let I16x3 { x, y, .. } = lsm303dlhc.mag().unwrap();

        // Look at the signs of the X and Y components to determine in which
        // quadrant the magnetic field is
        let dir = match (x &gt; 0, y &gt; 0) {
            // Quadrant I
            (true, true) =&gt; Direction::Southeast,
            // Quadrant II
            (false, true) =&gt; Direction::Northeast,
            // Quadrant III
            (false, false) =&gt; Direction::Northwest,
            // Quadrant IV
            (true, false) =&gt; Direction::Southwest,
        };

        leds.iter_mut().for_each(|led| led.off().unwrap());
        leds[dir as usize].on().unwrap();

        delay.delay_ms(1_000_u16);
    }
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="take-2"><a class="header" href="#take-2">Take 2</a></h1>
<p>This time, we'll use math to get the precise angle that the magnetic field forms with the X and Y
axes of the magnetometer.</p>
<p>We'll use the <code>atan2</code> function. This function returns an angle in the <code>-PI</code> to <code>PI</code> range. The
graphic below shows how this angle is measured:</p>
<p align="center">
<img class="white_bg" title="atan2" src="https://upload.wikimedia.org/wikipedia/commons/0/03/Atan2_60.svg">
</p>
<p>Although not explicitly shown in this graph the X axis points to the right and the Y axis points up.</p>
<p>Here's the starter code. <code>theta</code>, in radians, has already been computed. You need to pick which LED
to turn on based on the value of <code>theta</code>.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

// You'll find this useful ;-)
use core::f32::consts::PI;

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*, switch_hal::OutputSwitch, Direction, I16x3};
// this trait provides the `atan2` method
use m::Float;

#[entry]
fn main() -&gt; ! {
    let (leds, mut lsm303dlhc, mut delay, _itm) = aux15::init();
    let mut leds = leds.into_array();

    loop {
        let I16x3 { x, y, .. } = lsm303dlhc.mag().unwrap();

        let _theta = (y as f32).atan2(x as f32); // in radians

        // FIXME pick a direction to point to based on `theta`
        let dir = Direction::Southeast;

        leds.iter_mut().for_each(|led| led.off().unwrap());
        leds[dir as usize].on().unwrap();

        delay.delay_ms(100_u8);
    }
}
</code></pre></pre>
<p>Suggestions/tips:</p>
<ul>
<li>A whole circle rotation equals 360 degrees.</li>
<li><code>PI</code> radians is equivalent to 180 degrees.</li>
<li>If <code>theta</code> was zero, what LED would you turn on?</li>
<li>If <code>theta</code> was, instead, very close to zero, what LED would you turn on?</li>
<li>If <code>theta</code> kept increasing, at what value would you turn on a different LED?</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="solution-2"><a class="header" href="#solution-2">Solution 2</a></h1>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

// You'll find this useful ;-)
use core::f32::consts::PI;

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*, switch_hal::OutputSwitch, Direction, I16x3};
use m::Float;

#[entry]
fn main() -&gt; ! {
    let (leds, mut lsm303dlhc, mut delay, _itm) = aux15::init();
    let mut leds = leds.into_array();

    loop {
        let I16x3 { x, y, .. } = lsm303dlhc.mag().unwrap();

        let theta = (y as f32).atan2(x as f32); // in radians

        let dir = if theta &lt; -7. * PI / 8. {
            Direction::North
        } else if theta &lt; -5. * PI / 8. {
            Direction::Northwest
        } else if theta &lt; -3. * PI / 8. {
            Direction::West
        } else if theta &lt; -PI / 8. {
            Direction::Southwest
        } else if theta &lt; PI / 8. {
            Direction::South
        } else if theta &lt; 3. * PI / 8. {
            Direction::Southeast
        } else if theta &lt; 5. * PI / 8. {
            Direction::East
        } else if theta &lt; 7. * PI / 8. {
            Direction::Northeast
        } else {
            Direction::North
        };

        leds.iter_mut().for_each(|led| led.off().unwrap());
        leds[dir as usize].on().unwrap();

        delay.delay_ms(100_u8);
    }
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="magnitude"><a class="header" href="#magnitude">Magnitude</a></h1>
<p>We have been working with the direction of the magnetic field but what's its real magnitude? The
number that the <code>magnetic_field</code> function reports are unit-less. How can we convert those values to
Gauss?</p>
<p>The documentation will answer that question.</p>
<blockquote>
<p>Section 2.1 Sensor characteristics - Page 10 - LSM303DLHC Data Sheet</p>
</blockquote>
<p>The table in that page shows a <em>magnetic gain setting</em> that has different values according to the
values of the GN bits. By default, those GN bits are set to <code>001</code>. That means that magnetic gain of
the X and Y axes is <code>1100 LSB / Gauss</code> and the magnetic gain of the Z axis is <code>980 LSB / Gauss</code>. LSB
stands for Least Significant Bits and the <code>1100 LSB / Gauss</code> number indicates that a reading of
<code>1100</code> is equivalent to <code>1 Gauss</code>, a reading of <code>2200</code> is equivalent to 2 Gauss and so on.</p>
<p>So, what we need to do is divide the X, Y and Z values that the sensor outputs by its corresponding
<em>gain</em>. Then, we'll have the X, Y and Z components of the magnetic field in Gauss.</p>
<p>With some extra math we can retrieve the magnitude of the magnetic field from its X, Y and Z
components:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let magnitude = (x * x + y * y + z * z).sqrt();
<span class="boring">}
</span></code></pre></pre>
<p>Putting all this together in a program:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*, I16x3};
use m::Float;

#[entry]
fn main() -&gt; ! {
    const XY_GAIN: f32 = 1100.; // LSB / G
    const Z_GAIN: f32 = 980.; // LSB / G

    let (_leds, mut lsm303dlhc, mut delay, mut itm) = aux15::init();

    loop {
        let I16x3 { x, y, z } = lsm303dlhc.mag().unwrap();

        let x = f32::from(x) / XY_GAIN;
        let y = f32::from(y) / XY_GAIN;
        let z = f32::from(z) / Z_GAIN;

        let mag = (x * x + y * y + z * z).sqrt();

        iprintln!(&amp;mut itm.stim[0], &quot;{} mG&quot;, mag * 1_000.);

        delay.delay_ms(500_u16);
    }
}
</code></pre></pre>
<p>This program will report the magnitude (strength) of the magnetic field in milligauss (<code>mG</code>). The
magnitude of the Earth's magnetic field is in the range of <code>250 mG</code> to <code>650 mG</code> (the magnitude
varies depending on your geographical location) so you should see a value in that range or close to
that range -- I see a magnitude of around 210 mG.</p>
<p>Some questions:</p>
<p>Without moving the board, what value do you see? Do you always see the same value?</p>
<p>If you rotate the board, does the magnitude change? Should it change?</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="calibration"><a class="header" href="#calibration">Calibration</a></h1>
<p>If we rotate the board, the direction of the Earth's magnetic field with respect to the magnetometer
should change but its magnitude should not! Yet, the magnetometer indicates that the magnitude of
the magnetic field changes as the board rotates.</p>
<p>Why's that the case? Turns out the magnetometer needs to be calibrated to return the correct answer.</p>
<p>The calibration involves quite a bit of math (matrices) so we won't cover it here but this
<a href="https://www.nxp.com/docs/en/application-note/AN4246.pdf">Application Note</a> describes the procedure if you are interested. Instead, what we'll do in this
section is <em>visualize</em> how off we are.</p>
<p>Let's try this experiment: Let's record the readings of the magnetometer while we slowly rotate the
board in different directions. We'll use the <code>iprintln</code> macro to format the readings as Tab
Separated Values (TSV).</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux15::{entry, iprint, iprintln, prelude::*, I16x3};

#[entry]
fn main() -&gt; ! {
    let (_leds, mut lsm303dlhc, mut delay, mut itm) = aux15::init();

    loop {
        let I16x3 { x, y, z } = lsm303dlhc.mag().unwrap();

        iprintln!(&amp;mut itm.stim[0], &quot;{}\t{}\t{}&quot;, x, y, z);

        delay.delay_ms(100_u8);
    }
}
</code></pre></pre>
<p>You should get an output in the console that looks like this:</p>
<pre><code class="language-console">$ # itmdump console
-76     213     -54
-76     213     -54
-76     213     -54
-76     213     -54
-73     213     -55
</code></pre>
<p>You can pipe that to a file using:</p>
<pre><code class="language-console">$ # Careful! Exit any running other `itmdump` instance that may be running
$ itmdump -F -f itm.txt &gt; emf.txt
</code></pre>
<p>Rotate the board in many different direction while you log data for a several seconds.</p>
<p>Then import that TSV file into a spreadsheet program (or use the Python script shown below) and plot
the first two columns as a scatter plot.</p>
<pre><code class="language-python">#!/usr/bin/python

import csv
import math
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import sys

# apply plot style
sns.set()

x = []
y = []

with open(sys.argv[1], 'r') as f:
    rows = csv.reader(f, delimiter='\t')

    for row in rows:
        # discard rows that are missing data
        if len(row) != 3 or not row[0] or not row[1]:
            continue

        x.append(int(row[0]))
        y.append(int(row[1]))

r = math.ceil(max(max(np.abs(x)), max(np.abs(y))) / 100) * 100

plt.plot(x, y, '.')
plt.xlim(-r, r)
plt.ylim(-r, r)
plt.gca().set_aspect(1)
plt.tight_layout()

plt.savefig('emf.svg')
plt.close
</code></pre>
<p align="center">
<img title="Earth's magnetic field" src="15-led-compass/../assets/emf.svg">
</p>
<p>If you rotated the board on a flat horizontal surface, the Z component of the magnetic field should
have remained relatively constant and this plot should have been a circumference (not a ellipse)
centered at the origin. If you rotated the board in random directions, which was the case of plot
above, then you should have gotten a circle made of a bunch of points centered at the origin.
Deviations from the circle shape indicate that the magnetometer needs to be calibrated.</p>
<p>Take home message: Don't just trust the reading of a sensor. Verify it's outputting sensible values.
If it's not, then calibrate it.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="punch-o-meter"><a class="header" href="#punch-o-meter">Punch-o-meter</a></h1>
<p>In this section we'll be playing with the accelerometer that's in the board.</p>
<p>What are we building this time? A punch-o-meter! We'll be measuring the power of your jabs. Well,
actually the maximum acceleration that you can reach because acceleration is what accelerometers
measure. Strength and acceleration are proportional though so it's a good approximation.</p>
<p>The accelerometer is also built inside the LSM303DLHC package. And just like the magnetometer, it
can also be accessed using the I2C bus. It also has the same coordinate system as the magnetometer.
Here's the coordinate system again:</p>
<p align="center">
<img height=480 title="Magnetometer axes" src="16-punch-o-meter/../assets/f3-lsm303dlhc.png">
</p>
<p>Just like in the previous unit, we'll be using a high level API to directly get the sensor readings
in a nicely packaged <code>struct</code>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="gravity-is-up"><a class="header" href="#gravity-is-up">Gravity is up?</a></h1>
<p>What's the first thing we'll do?</p>
<p>Perform a sanity check!</p>
<p>The starter code prints the X, Y and Z components of the acceleration measured by the accelerometer.
The values have already been &quot;scaled&quot; and have units of <code>g</code>s. Where <code>1 g</code> is equal to the
acceleration of the gravity, about <code>9.8</code> meters per second squared.</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux16::{entry, iprint, iprintln, prelude::*, I16x3, Sensitivity};

#[entry]
fn main() -&gt; ! {
    let (mut lsm303dlhc, mut delay, _mono_timer, mut itm) = aux16::init();

    // extend sensing range to `[-12g, +12g]`
    lsm303dlhc.set_accel_sensitivity(Sensitivity::G12).unwrap();
    loop {
        const SENSITIVITY: f32 = 12. / (1 &lt;&lt; 14) as f32;

        let I16x3 { x, y, z } = lsm303dlhc.accel().unwrap();

        let x = f32::from(x) * SENSITIVITY;
        let y = f32::from(y) * SENSITIVITY;
        let z = f32::from(z) * SENSITIVITY;

        iprintln!(&amp;mut itm.stim[0], &quot;{:?}&quot;, (x, y, z));

        delay.delay_ms(1_000_u16);
    }
}
</code></pre></pre>
<p>The output of this program with the board sitting still will be something like:</p>
<pre><code class="language-console">$ # itmdump console
(..)
(0.0, 0.0, 1.078125)
(0.0, 0.0, 1.078125)
(0.0, 0.0, 1.171875)
(0.0, 0.0, 1.03125)
(0.0, 0.0, 1.078125)
</code></pre>
<p>Which is weird because the board is not moving yet its acceleration is non-zero. What's going on?
This must be related to the gravity, right? Because the acceleration of gravity is <code>1 g</code>. But the
gravity pulls objects downwards so the acceleration along the Z axis should be negative not positive
...</p>
<p>Did the program get the Z axis backwards? Nope, you can test rotating the board to align the gravity
to the X or Y axis but the acceleration measured by the accelerometer is always pointing up.</p>
<p>What happens here is that the accelerometer is measuring the <em>proper acceleration</em> of the board not
the acceleration <em>you</em> are observing. This proper acceleration is the acceleration of the board as
seen from a observer that's in free fall. An observer that's in free fall is moving toward the
center of the the Earth with an acceleration of <code>1g</code>; from its point of view the board is actually
moving upwards (away from the center of the Earth) with an acceleration of <code>1g</code>. And that's why the
proper acceleration is pointing up. This also means that if the board was in free fall, the
accelerometer would report a proper acceleration of zero. Please, don't try that at home.</p>
<p>Yes, physics is hard. Let's move on.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="the-challenge-1"><a class="header" href="#the-challenge-1">The challenge</a></h1>
<p>To keep things simple, we'll measure the acceleration only in the X axis while the board remains
horizontal. That way we won't have to deal with subtracting that <em>fictitious</em> <code>1g</code> we observed
before which would be hard because that <code>1g</code> could have X Y Z components depending on how the board
is oriented.</p>
<p>Here's what the punch-o-meter must do:</p>
<ul>
<li>By default, the app is not &quot;observing&quot; the acceleration of the board.</li>
<li>When a significant X acceleration is detected (i.e. the acceleration goes above some threshold),
the app should start a new measurement.</li>
<li>During that measurement interval, the app should keep track of the maximum acceleration observed</li>
<li>After the measurement interval ends, the app must report the maximum acceleration observed. You
can report the value using the <code>iprintln</code> macro.</li>
</ul>
<p>Give it a try and let me know how hard you can punch <code>;-)</code>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="my-solution-2"><a class="header" href="#my-solution-2">My solution</a></h1>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

#[allow(unused_imports)]
use aux16::{entry, iprint, iprintln, prelude::*, I16x3, Sensitivity};
use m::Float;

#[entry]
fn main() -&gt; ! {
    const SENSITIVITY: f32 = 12. / (1 &lt;&lt; 14) as f32;
    const THRESHOLD: f32 = 0.5;

    let (mut lsm303dlhc, mut delay, mono_timer, mut itm) = aux16::init();

    lsm303dlhc.set_accel_sensitivity(Sensitivity::G12).unwrap();

    let measurement_time = mono_timer.frequency().0; // 1 second in ticks
    let mut instant = None;
    let mut max_g = 0.;
    loop {
        let g_x = f32::from(lsm303dlhc.accel().unwrap().x).abs() * SENSITIVITY;

        match instant {
            None =&gt; {
                // If acceleration goes above a threshold, we start measuring
                if g_x &gt; THRESHOLD {
                    iprintln!(&amp;mut itm.stim[0], &quot;START!&quot;);

                    max_g = g_x;
                    instant = Some(mono_timer.now());
                }
            }
            // Still measuring
            Some(ref instant) if instant.elapsed() &lt; measurement_time =&gt; {
                if g_x &gt; max_g {
                    max_g = g_x;
                }
            }
            _ =&gt; {
                // Report max value
                iprintln!(&amp;mut itm.stim[0], &quot;Max acceleration: {}g&quot;, max_g);

                // Measurement done
                instant = None;

                // Reset
                max_g = 0.;
            }
        }

        delay.delay_ms(50_u8);
    }
}
</code></pre></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="whats-left-for-you-to-explore"><a class="header" href="#whats-left-for-you-to-explore">What's left for you to explore</a></h1>
<p>We have barely scratched the surface! There's lots of stuff left for you to
explore.</p>
<blockquote>
<p><strong>NOTE:</strong> If you're reading this, and you'd like to help add examples or
exercises to the Discovery book for any of the items below, or any other
relevant embedded topics, we'd love to have your help!</p>
<p>Please <a href="https://github.com/rust-embedded/discovery/issues/new">open an issue</a> if you would like to help, but need assistance or
mentoring for how to contribute this to the book, or open a Pull Request
adding the information!</p>
</blockquote>
<h2 id="topics-about-embedded-software"><a class="header" href="#topics-about-embedded-software">Topics about embedded software</a></h2>
<p>These topics discuss strategies for writing embedded software. Although many
problems can be solved in different ways, these sections talk about some
strategies, and when they make sense (or don't make sense) to use.</p>
<h3 id="multitasking"><a class="header" href="#multitasking">Multitasking</a></h3>
<p>All our programs executed a single task. How could we achieve multitasking in a
system with no OS, and thus no threads. There are two main approaches to
multitasking: preemptive multitasking and cooperative multitasking.</p>
<p>In preemptive multitasking a task that's currently being executed can, at any point in time, be
<em>preempted</em> (interrupted) by another task. On preemption, the first task will be suspended and the
processor will instead execute the second task. At some point the first task will be resumed.
Microcontrollers provide hardware support for preemption in the form of <em>interrupts</em>.</p>
<p>In cooperative multitasking a task that's being executed will run until it reaches a <em>suspension
point</em>. When the processor reaches that suspension point it will stop executing the current task and
instead go and execute a different task. At some point the first task will be resumed. The main
difference between these two approaches to multitasking is that in cooperative multitasking <em>yields</em>
execution control at <em>known</em> suspension points instead of being forcefully preempted at any point of
its execution.</p>
<h3 id="sleeping"><a class="header" href="#sleeping">Sleeping</a></h3>
<p>All our programs have been continuously polling peripherals to see if there's
anything that needs to be done. However, some times there's nothing to be done!
At those times, the microcontroller should &quot;sleep&quot;.</p>
<p>When the processor sleeps, it stops executing instructions and this saves power.
It's almost always a good idea to save power so your microcontroller should be
sleeping as much as possible. But, how does it know when it has to wake up to
perform some action? &quot;Interrupts&quot; are one of the events that wake up the
microcontroller but there are others and the <code>wfi</code> and <code>wfe</code> are the
instructions that make the processor &quot;sleep&quot;.</p>
<h2 id="topics-related-to-microcontroller-capabilities"><a class="header" href="#topics-related-to-microcontroller-capabilities">Topics related to microcontroller capabilities</a></h2>
<p>Microcontrollers (like our STM32F3) have many different capabilities. However, many share similar
capabilities that can be used to solve all sorts of different problems.</p>
<p>These topics discuss some of those capabilities, and how they can be used effectively
in embedded development.</p>
<h3 id="direct-memory-access-dma"><a class="header" href="#direct-memory-access-dma">Direct Memory Access (DMA).</a></h3>
<p>This peripheral is a kind of <em>asynchronous</em> <code>memcpy</code>. So far our programs have
been pumping data, byte by byte, into peripherals like UART and I2C. This DMA
peripheral can be used to perform bulk transfers of data. Either from RAM to
RAM, from a peripheral, like a UART, to RAM or from RAM to a peripheral. You can
schedule a DMA transfer, like read 256 bytes from USART1 into this buffer, leave
it running in the background and then poll some register to see if it has
completed so you can do other stuff while the transfer is ongoing.</p>
<h3 id="interrupts"><a class="header" href="#interrupts">Interrupts</a></h3>
<p>In order to interact with the real world, it is often necessary for the
microcontroller to respond <em>immediately</em> when some kind of event occurs.</p>
<p>Microcontrollers have the ability to be interrupted, meaning when a certain event
occurs, it will stop whatever it is doing at the moment, to instead respond to that
event. This can be very useful when we want to stop a motor when a button is pressed,
or measure a sensor when a timer finishes counting down.</p>
<p>Although these interrupts can be very useful, they can also be a bit difficult
to work with properly. We want to make sure that we respond to events quickly,
but also allow other work to continue as well.</p>
<p>In Rust, we model interrupts similar to the concept of threading on desktop Rust
programs. This means we also must think about the Rust concepts of <code>Send</code> and <code>Sync</code>
when sharing data between our main application, and code that executes as part of
handling an interrupt event.</p>
<h3 id="pulse-width-modulation-pwm"><a class="header" href="#pulse-width-modulation-pwm">Pulse Width Modulation (PWM)</a></h3>
<p>In a nutshell, PWM is turning on something and then turning it off periodically
while keeping some proportion (&quot;duty cycle&quot;) between the &quot;on time&quot; and the &quot;off
time&quot;. When used on a LED with a sufficiently high frequency, this can be used
to dim the LED. A low duty cycle, say 10% on time and 90% off time, will make
the LED very dim wheres a high duty cycle, say 90% on time and 10% off time,
will make the LED much brighter (almost as if it were fully powered).</p>
<p>In general, PWM can be used to control how much <em>power</em> is given to some
electric device. With proper (power) electronics between a microcontroller and
an electrical motor, PWM can be used to control how much power is given to the
motor thus it can be used to control its torque and speed. Then you can add an
angular position sensor and you got yourself a closed loop controller that can
control the position of the motor at different loads.</p>
<h3 id="digital-inputs"><a class="header" href="#digital-inputs">Digital inputs</a></h3>
<p>We have used the microcontroller pins as digital outputs, to drive LEDs. But
these pins can also be configured as digital inputs. As digital inputs, these
pins can read the binary state of switches (on/off) or buttons (pressed/not
pressed).</p>
<p>(<em>spoilers</em> reading the binary state of switches / buttons is not as
straightforward as it sounds ;-)</p>
<h3 id="analog-to-digital-converters-adc"><a class="header" href="#analog-to-digital-converters-adc">Analog-to-Digital Converters (ADC)</a></h3>
<p>There are a lots of digital sensors out there. You can use a protocol like I2C
and SPI to read them. But analog sensors also exist! These sensors just output a
voltage level that's proportional to the magnitude they are sensing.</p>
<p>The ADC peripheral can be use to convert that &quot;analog&quot; voltage level, say <code>1.25</code>
Volts,into a &quot;digital&quot; number, say in the <code>[0, 65535]</code> range, that the processor
can use in its calculations.</p>
<h3 id="digital-to-analog-converters-dac"><a class="header" href="#digital-to-analog-converters-dac">Digital-to-Analog Converters (DAC)</a></h3>
<p>As you might expect a DAC is exactly the opposite of ADC. You can write some
digital value into a register to produce a voltage in the <code>[0, 3.3V]</code> range
(assuming a <code>3.3V</code> power supply) on some &quot;analog&quot; pin. When this analog pin is
connected to some appropriate electronics and the register is written to at some
constant, fast rate (frequency) with the right values you can produce sounds or
even music!</p>
<h3 id="real-time-clock-rtc"><a class="header" href="#real-time-clock-rtc">Real Time Clock (RTC)</a></h3>
<p>This peripheral can be used to track time in &quot;human format&quot;. Seconds, minutes,
hours, days, months and years. This peripheral handles the translation from
&quot;ticks&quot; to these human friendly units of time. It even handles leap years and
Daylight Save Time for you!</p>
<h3 id="other-communication-protocols"><a class="header" href="#other-communication-protocols">Other communication protocols</a></h3>
<p>SPI, I2S, SMBUS, CAN, IrDA, Ethernet, USB, Bluetooth, etc.</p>
<p>Different applications use different communication protocols. User facing
applications usually have an USB connector because USB is an ubiquitous
protocol in PCs and smartphones. Whereas inside cars you'll find plenty of CAN
&quot;buses&quot;. Some digital sensors use SPI, others use I2C and others, SMBUS.</p>
<h2 id="general-embedded-relevant-topics"><a class="header" href="#general-embedded-relevant-topics">General Embedded-Relevant Topics</a></h2>
<p>These topics cover items that are not specific to our device, or the hardware on
it. Instead, they discuss useful techniques that could be used on embedded
systems.</p>
<h3 id="gyroscopes"><a class="header" href="#gyroscopes">Gyroscopes</a></h3>
<p>As part of our Punch-o-meter exercise, we used the Accelerometer to measure
changes in acceleration in three dimensions. Our board also features a sensor
called a Gyroscope, which allows us to measure changes in &quot;spin&quot; in three
dimensions.</p>
<p>This can be very useful when trying to build certain systems, such as a robot
that wants to avoid tipping over. Additionally, the data from a sensor like a
gyroscope can also be combined with data from accelerometer using a technique
called Sensor Fusion (see below for more information).</p>
<h3 id="servo-and-stepper-motors"><a class="header" href="#servo-and-stepper-motors">Servo and Stepper Motors</a></h3>
<p>While some motors are used primarily just to spin in one direction or the other,
for example driving a remote control car forwards or backwards, it is sometimes
useful to measure more precisely how a motor rotates.</p>
<p>Our microcontroller can be used to drive Servo or Stepper motors, which allow
for more precise control of how many turns are being made by the motor, or
can even position the motor in one specific place, for example if we wanted to
move the arms of a clock to a particular direction.</p>
<h3 id="sensor-fusion"><a class="header" href="#sensor-fusion">Sensor fusion</a></h3>
<p>The STM32F3DISCOVERY contains three motion sensors: an accelerometer, a
gyroscope and a magnetometer. On their own these measure: (proper) acceleration,
angular speed and (the Earth's) magnetic field. But these magnitudes can be
&quot;fused&quot; into something more useful: a &quot;robust&quot; measurement of the orientation of
the board. Where robust means with less measurement error than a single sensor
would be capable of.</p>
<p>This idea of deriving more reliable data from different sources is known as
sensor fusion.</p>
<hr />
<p>So where to next? There are several options:</p>
<ul>
<li>You could check out the examples in the <a href="https://docs.rs/f3"><code>f3</code></a> board support crate. All those examples work for
the STM32F3DISCOVERY board you have.</li>
</ul>
<ul>
<li>You could try out <a href="https://mobile.twitter.com/japaricious/status/962770003325005824">this motion sensors demo</a>. Details about the implementation and
source code are available in <a href="http://blog.japaric.io/wd-1-2-l3gd20-lsm303dlhc-madgwick/">this blog post</a>.</li>
</ul>
<ul>
<li>You could check out <a href="https://docs.rs/cortex-m-rtfm">Real Time for The Masses</a>. A very efficient preemptive multitasking framework
that supports task prioritization and dead lock free execution.</li>
</ul>
<ul>
<li>You could try running Rust on a different development board. The easiest way to get started is to
use the <a href="https://docs.rs/cortex-m-quickstart/0.2.4/cortex_m_quickstart"><code>cortex-m-quickstart</code></a> Cargo project template.</li>
</ul>
<ul>
<li>You could check out <a href="http://blog.japaric.io/brave-new-io/">this blog post</a> which describes how Rust type system can
prevent bugs in I/O configuration.</li>
</ul>
<ul>
<li>You could check out my <a href="http://blog.japaric.io">blog</a> for miscellaneous topics about embedded development with Rust.</li>
</ul>
<ul>
<li>You could check out the <a href="https://github.com/rust-embedded/embedded-hal"><code>embedded-hal</code></a> project which aims to build abstractions (traits) for all
the embedded I/O functionality commonly found on microcontrollers.</li>
</ul>
<ul>
<li>You could join the <a href="https://github.com/rust-lang-nursery/embedded-wg/issues/39">Weekly driver initiative</a> and help us write generic drivers on top of the
<code>embedded-hal</code> traits and that work for all sorts of platforms (ARM Cortex-M, AVR, MSP430, RISCV,
etc.)</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="general-troubleshooting"><a class="header" href="#general-troubleshooting">General troubleshooting</a></h1>
<h2 id="openocd-problems"><a class="header" href="#openocd-problems">OpenOCD problems</a></h2>
<h3 id="cant-connect-to-openocd---error-open-failed"><a class="header" href="#cant-connect-to-openocd---error-open-failed">can't connect to OpenOCD - &quot;Error: open failed&quot;</a></h3>
<h4 id="symptoms"><a class="header" href="#symptoms">Symptoms</a></h4>
<p>Upon trying to establish a <em>new connection</em> with the device you get an error
that looks like this:</p>
<pre><code>$ openocd -f (..)
(..)
Error: open failed
in procedure 'init'
in procedure 'ocd_bouncer'
</code></pre>
<h4 id="cause"><a class="header" href="#cause">Cause</a></h4>
<p>The device is not (properly) connected or not the correct ST-LINK interface
configuration is used.</p>
<h4 id="fix"><a class="header" href="#fix">Fix</a></h4>
<p>Linux:</p>
<ul>
<li>Check the USB connection using <code>lsusb</code>.</li>
<li>You may not have enough permission to open the device. Try again with <code>sudo</code>.
If that works, you can use <a href="appendix/1-general-troubleshooting/../../03-setup/linux.html#udev-rules">these instructions</a> to make OpenOCD work without
root privilege.</li>
<li>You might be using the wrong interface configuration for your ST-LINK.
Try <code>interface/stlink-v2.cfg</code> instead of <code>interface/stlink-v2-1.cfg</code>.</li>
</ul>
<p>Windows:</p>
<ul>
<li>You are probably missing the ST-LINK USB driver. Installation instructions
<a href="appendix/1-general-troubleshooting/../../03-setup/windows.html#st-link-usb-driver">here</a>.</li>
</ul>
<h3 id="cant-connect-to-openocd---polling-again-in-x00ms"><a class="header" href="#cant-connect-to-openocd---polling-again-in-x00ms">can't connect to OpenOCD - &quot;Polling again in X00ms&quot;</a></h3>
<h4 id="symptoms-1"><a class="header" href="#symptoms-1">Symptoms</a></h4>
<p>Upon trying to establish a <em>new connection</em> with the device you get an error
that looks like this:</p>
<pre><code>$ openocd -f (..)
(..)
Error: jtag status contains invalid mode value - communication failure
Polling target stm32f3x.cpu failed, trying to reexamine
Examination failed, GDB will be halted. Polling again in 100ms
Info : Previous state query failed, trying to reconnect
Error: jtag status contains invalid mode value - communication failure
Polling target stm32f3x.cpu failed, trying to reexamine
Examination failed, GDB will be halted. Polling again in 300ms
Info : Previous state query failed, trying to reconnect
</code></pre>
<h4 id="cause-1"><a class="header" href="#cause-1">Cause</a></h4>
<p>The microcontroller may have get stuck in some tight infinite loop or it may be
continuously raising an exception, e.g. the exception handler is raising an
exception.</p>
<h4 id="fix-1"><a class="header" href="#fix-1">Fix</a></h4>
<ul>
<li>Close OpenOCD, if running</li>
<li>Press and hold the reset (black) button</li>
<li>Launch the OpenOCD command</li>
<li>Now, release the reset button</li>
</ul>
<h3 id="openocd-connection-lost---polling-again-in-x00ms"><a class="header" href="#openocd-connection-lost---polling-again-in-x00ms">OpenOCD connection lost - &quot;Polling again in X00ms&quot;</a></h3>
<h4 id="symptoms-2"><a class="header" href="#symptoms-2">Symptoms</a></h4>
<p>A <em>running</em> OpenOCD session suddenly errors with:</p>
<pre><code># openocd -f (..)
Error: jtag status contains invalid mode value - communication failure
Polling target stm32f3x.cpu failed, trying to reexamine
Examination failed, GDB will be halted. Polling again in 100ms
Info : Previous state query failed, trying to reconnect
Error: jtag status contains invalid mode value - communication failure
Polling target stm32f3x.cpu failed, trying to reexamine
Examination failed, GDB will be halted. Polling again in 300ms
Info : Previous state query failed, trying to reconnect
</code></pre>
<h4 id="cause-2"><a class="header" href="#cause-2">Cause</a></h4>
<p>The USB connection was lost.</p>
<h4 id="fix-2"><a class="header" href="#fix-2">Fix</a></h4>
<ul>
<li>Close OpenOCD</li>
<li>Disconnect and re-connect the USB cable.</li>
<li>Re-launch OpenOCD</li>
</ul>
<h3 id="cant-flash-the-device---ignoring-packet-error-continuing"><a class="header" href="#cant-flash-the-device---ignoring-packet-error-continuing">Can't flash the device - &quot;Ignoring packet error, continuing...&quot;</a></h3>
<h4 id="symptoms-3"><a class="header" href="#symptoms-3">Symptoms</a></h4>
<p>While flashing the device, you get:</p>
<pre><code>$ arm-none-eabi-gdb $file
Start address 0x8000194, load size 31588
Transfer rate: 22 KB/sec, 5264 bytes/write.
Ignoring packet error, continuing...
Ignoring packet error, continuing...
</code></pre>
<h4 id="cause-3"><a class="header" href="#cause-3">Cause</a></h4>
<p>Closed <code>itmdump</code> while a program that &quot;printed&quot; to the ITM was running. The
current GDB session will appear to work normally, just without ITM output but
the next GDB session will error with the message that was shown in the previous
section.</p>
<p>Or, <code>itmdump</code> was called <strong>after</strong> the <code>monitor tpiu</code> was issued thus making
<code>itmdump</code> delete the file / named-pipe that OpenOCD was writing to.</p>
<h4 id="fix-3"><a class="header" href="#fix-3">Fix</a></h4>
<ul>
<li>Close/kill GDB, OpenOCD and <code>itmdump</code></li>
<li>Remove the file / named-pipe that <code>itmdump</code> was using (for example,
<code>itm.txt</code>).</li>
<li>Launch OpenOCD</li>
<li>Then, launch <code>itmdump</code></li>
<li>Then, launch the GDB session that executes the <code>monitor tpiu</code> command.</li>
</ul>
<h3 id="cant-connect-to-openocd---error-couldnt-bind-telnet-to-socket-address-already-in-use"><a class="header" href="#cant-connect-to-openocd---error-couldnt-bind-telnet-to-socket-address-already-in-use">can't connect to OpenOCD - &quot;Error: couldn't bind [telnet] to socket: Address already in use&quot;</a></h3>
<h4 id="symptoms-4"><a class="header" href="#symptoms-4">Symptoms</a></h4>
<p>Upon trying to establish a <em>new connection</em> with the device you get an error
that looks something like this:</p>
<pre><code>$ openocd -f (..)
(..)
Error: couldn't bind telnet to socket: Address already in use
</code></pre>
<h4 id="cause-4"><a class="header" href="#cause-4">Cause</a></h4>
<p>One or more of the ports OpenOCD requires access to, 3333, 4444, or 6666, is in use by another process. Each of these ports is used for another aspect: 3333 for gdb, 4444 for telnet, 6666 for remote procedure call (RPC) commands to TCL</p>
<h4 id="fix-4"><a class="header" href="#fix-4">Fix</a></h4>
<p>You can go two routes for fixing this. A) Kill any process that's using one of those ports. B) Specify different ports you know to be free for OpenOCD to use.</p>
<p>Solution A</p>
<p>Mac:</p>
<ul>
<li>Get a list of processes using ports by running <code>sudo lsof -PiTCP -sTCP:LISTEN</code></li>
<li>Kill the process(es) blocking the key ports by noting their pid(s) and running <code>kill [pid]</code> for each. (Assuming you can confirm they're not running anything mission-critical on your machine!)</li>
</ul>
<p>Solution B</p>
<p>All:</p>
<ul>
<li>Send configuration details to OpenOCD when starting it up so that it uses a different port from the default for any of the processes.</li>
<li>For example, to do its telnet features on 4441 instead of the default 4444, you would run <code>openocd -f interface/stlink-v2-1.cfg -f target/stm32f3x.cfg -c &quot;telnet_port 4441&quot;</code></li>
<li>More details on OpenOCD's Configuration Stage can be found in their [official docs online]: http://openocd.org/doc/html/Server-Configuration.html</li>
</ul>
<h2 id="cargo-problems"><a class="header" href="#cargo-problems">Cargo problems</a></h2>
<h3 id="cant-find-crate-for-core"><a class="header" href="#cant-find-crate-for-core">&quot;can't find crate for <code>core</code>&quot;</a></h3>
<h4 id="symptoms-5"><a class="header" href="#symptoms-5">Symptoms</a></h4>
<pre><code>   Compiling volatile-register v0.1.2
   Compiling rlibc v1.0.0
   Compiling r0 v0.1.0
error[E0463]: can't find crate for `core`

error: aborting due to previous error

error[E0463]: can't find crate for `core`

error: aborting due to previous error

error[E0463]: can't find crate for `core`

error: aborting due to previous error

Build failed, waiting for other jobs to finish...
Build failed, waiting for other jobs to finish...
error: Could not compile `r0`.

To learn more, run the command again with --verbose.
</code></pre>
<h4 id="cause-5"><a class="header" href="#cause-5">Cause</a></h4>
<p>You are using a toolchain older than <code>nightly-2018-04-08</code> and forgot to call <code>rustup target add thumbv7em-none-eabihf</code>.</p>
<h4 id="fix-5"><a class="header" href="#fix-5">Fix</a></h4>
<p>Update your nightly and install the <code>thumbv7em-none-eabihf</code> target.</p>
<pre><code class="language-console">$ rustup update nightly

$ rustup target add thumbv7em-none-eabihf
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="how-to-use-gdb"><a class="header" href="#how-to-use-gdb">How to use GDB</a></h1>
<p>Below are some useful GDB commands that can help us debug our programs. This assumes you have <a href="appendix/2-how-to-use-gdb/../../05-led-roulette/flash-it.html">flashed a program</a> onto your microcontroller and attached to an OpenOCD session.</p>
<h2 id="general-debugging"><a class="header" href="#general-debugging">General Debugging</a></h2>
<blockquote>
<p><strong>NOTE:</strong> Many of the commands you see below can be executed using a short form. For example, <code>continue</code> can simply be used as <code>c</code>, or <code>break $location</code> can be used as <code>b $location</code>. Once you have experience with the commands below, try to see how short you can get the commands to go before GDB doesn't recognize them!</p>
</blockquote>
<h3 id="dealing-with-breakpoints"><a class="header" href="#dealing-with-breakpoints">Dealing with Breakpoints</a></h3>
<ul>
<li><code>break $location</code>: Set a breakpoint at a place in your code. The value of <code>$location</code> can include:
<ul>
<li><code>break *main</code> - Break on the exact address of the function <code>main</code></li>
<li><code>break *0x080012f2</code> - Break on the exact memory location <code>0x080012f2</code></li>
<li><code>break 123</code> - Break on line 123 of the currently displayed file</li>
<li><code>break main.rs:123</code> - Break on line 123 of the file <code>main.rs</code></li>
</ul>
</li>
<li><code>info break</code>: Display current breakpoints</li>
<li><code>delete</code>: Delete all breakpoints
<ul>
<li><code>delete $n</code>: Delete breakpoint <code>$n</code> (<code>n</code> being a number. For example: <code>delete $2</code>)</li>
</ul>
</li>
<li><code>clear</code>: Delete breakpoint at next instruction
<ul>
<li><code>clear main.rs:$function</code>: Delete breakpoint at entry of <code>$function</code> in <code>main.rs</code></li>
<li><code>clear main.rs:123</code>: Delete breakpoint on line 123 of <code>main.rs</code></li>
</ul>
</li>
<li><code>enable</code>: Enable all set breakpoints
<ul>
<li><code>enable $n</code>: Enable breakpoint <code>$n</code></li>
</ul>
</li>
<li><code>disable</code>: Disable all set breakpoints
<ul>
<li><code>disable $n</code>: Disable breakpoint <code>$n</code></li>
</ul>
</li>
</ul>
<h3 id="controlling-execution"><a class="header" href="#controlling-execution">Controlling Execution</a></h3>
<ul>
<li><code>continue</code>: Begin or continue execution of your program</li>
<li><code>next</code>: Execute the next line of your program
<ul>
<li><code>next $n</code>: Repeat <code>next</code> <code>$n</code> number times</li>
</ul>
</li>
<li><code>nexti</code>: Same as <code>next</code> but with machine instructions instead</li>
<li><code>step</code>: Execute the next line, if the next line includes a call to another function, step into that code
<ul>
<li><code>step $n</code>: Repeat <code>step</code> <code>$n</code> number times</li>
</ul>
</li>
<li><code>stepi</code>: Same as <code>step</code> but with machine instructions instead</li>
<li><code>jump $location</code>: Resume execution at specified location:
<ul>
<li><code>jump 123</code>: Resume execution at line 123</li>
<li><code>jump 0x080012f2</code>: Resume execution at address 0x080012f2</li>
</ul>
</li>
</ul>
<h3 id="printing-information"><a class="header" href="#printing-information">Printing Information</a></h3>
<ul>
<li><code>print /$f $data</code> - Print the value contained by the variable <code>$data</code>. Optionally format the output with <code>$f</code>, which can include:
<pre><code class="language-txt">x: hexadecimal 
d: signed decimal
u: unsigned decimal
o: octal
t: binary
a: address
c: character
f: floating point
</code></pre>
<ul>
<li><code>print /t 0xA</code>: Prints the hexadecimal value <code>0xA</code> as binary (0b1010)</li>
</ul>
</li>
<li><code>x /$n$u$f $address</code>: Examine memory at <code>$address</code>. Optionally, <code>$n</code> define the number of units to display, <code>$u</code> unit size (bytes, halfwords, words, etc), <code>$f</code> any <code>print</code> format defined above
<ul>
<li><code>x /5i 0x080012c4</code>: Print 5 machine instructions staring at address <code>0x080012c4</code></li>
<li><code>x/4xb $pc</code>: Print 4 bytes of memory starting where <code>$pc</code> currently is pointing</li>
</ul>
</li>
<li><code>disassemble $location</code>
<ul>
<li><code>disassemble /r main</code>: Disassemble the function <code>main</code>, using <code>/r</code> to show the bytes that make up each instruction</li>
</ul>
</li>
</ul>
<h3 id="looking-at-the-symbol-table"><a class="header" href="#looking-at-the-symbol-table">Looking at the Symbol Table</a></h3>
<ul>
<li><code>info functions $regex</code>: Print the names and data types of functions matched by <code>$regex</code>, omit <code>$regex</code> to print all functions
<ul>
<li><code>info functions main</code>: Print names and types of defined functions that contain the word <code>main</code></li>
</ul>
</li>
<li><code>info address $symbol</code>: Print where <code>$symbol</code> is stored in memory
<ul>
<li><code>info address GPIOC</code>: Print the memory address of the variable <code>GPIOC</code></li>
</ul>
</li>
<li><code>info variables $regex</code>: Print names and types of global variables matched by <code>$regex</code>, omit <code>$regex</code> to print all global variables</li>
<li><code>ptype $data</code>: Print more detailed information about <code>$data</code>
<ul>
<li><code>ptype cp</code>: Print detailed type information about the variable <code>cp</code> </li>
</ul>
</li>
</ul>
<h3 id="poking-around-the-program-stack"><a class="header" href="#poking-around-the-program-stack">Poking around the Program Stack</a></h3>
<ul>
<li><code>backtrace $n</code>: Print trace of <code>$n</code> frames, or omit <code>$n</code> to print all frames
<ul>
<li><code>backtrace 2</code>: Print trace of first 2 frames</li>
</ul>
</li>
<li><code>frame $n</code>: Select frame with number or address <code>$n</code>, omit <code>$n</code> to display current frame</li>
<li><code>up $n</code>: Select frame <code>$n</code> frames up</li>
<li><code>down $n</code>: Select frame <code>$n</code> frames down</li>
<li><code>info frame $address</code>: Describe frame at <code>$address</code>, omit <code>$address</code> for currently selected frame</li>
<li><code>info args</code>: Print arguments of selected frame</li>
<li><code>info registers $r</code>: Print the value of register <code>$r</code> in selected frame, omit <code>$r</code> for all registers
<ul>
<li><code>info registers $sp</code>: Print the value of the stack pointer register <code>$sp</code> in the current frame</li>
</ul>
</li>
</ul>
<h3 id="controlling-openocd-remotely"><a class="header" href="#controlling-openocd-remotely">Controlling OpenOCD Remotely</a></h3>
<ul>
<li><code>monitor reset run</code>: Reset the CPU, starting execution over again
<ul>
<li><code>monitor reset</code>: Same as above</li>
</ul>
</li>
<li><code>monitor reset init</code>: Reset the CPU, halting execution at the start</li>
<li><code>monitor targets</code>: Display information and state of current target</li>
</ul>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->


                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">

            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->

        <script type="text/javascript">
        window.addEventListener('load', function() {
            window.setTimeout(window.print, 100);
        });
        </script>

    </body>
</html>
